Skip to content

Commit

Permalink
Add Rust based LSP
Browse files Browse the repository at this point in the history
Signed-off-by: Micha Reiser <[email protected]>
  • Loading branch information
MichaReiser committed Sep 28, 2023
1 parent 8028de8 commit 02c6ea2
Show file tree
Hide file tree
Showing 33 changed files with 5,342 additions and 122 deletions.
366 changes: 366 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions crates/ruff_cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ruff_linter = { path = "../ruff_linter", features = ["clap"] }
ruff_cache = { path = "../ruff_cache" }
ruff_diagnostics = { path = "../ruff_diagnostics" }
ruff_formatter = { path = "../ruff_formatter" }
ruff_lsp = { path = "../ruff_lsp" }
ruff_notebook = { path = "../ruff_notebook" }
ruff_macros = { path = "../ruff_macros" }
ruff_python_ast = { path = "../ruff_python_ast" }
Expand Down Expand Up @@ -59,6 +60,8 @@ similar = { workspace = true }
strum = { workspace = true, features = [] }
thiserror = { workspace = true }
tracing = { workspace = true, features = ["log"] }
tracing-subscriber = { version="0.3.17",features = ["registry"] }
tracing-tree = "0.2.4"
walkdir = { version = "2.3.2" }
wild = { version = "2" }

Expand Down
42 changes: 39 additions & 3 deletions crates/ruff_cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ pub enum Command {
format: HelpFormat,
},
/// List or describe the available configuration options.
Config { option: Option<String> },
Config {
option: Option<String>,
},
/// List all supported upstream linters.
Linter {
/// Output format
Expand All @@ -63,11 +65,15 @@ pub enum Command {
Clean,
/// Generate shell completion.
#[clap(alias = "--generate-shell-completion", hide = true)]
GenerateShellCompletion { shell: clap_complete_command::Shell },
GenerateShellCompletion {
shell: clap_complete_command::Shell,
},
/// Run the Ruff formatter on the given files or directories.
#[doc(hidden)]
#[clap(hide = true)]
Format(FormatCommand),

Lsp(LspCommand),
}

// The `Parser` derive is for ruff_dev, for ruff_cli `Args` would be sufficient
Expand Down Expand Up @@ -397,6 +403,32 @@ pub struct FormatCommand {
no_preview: bool,
}

#[derive(Clone, Debug, clap::Parser)]
#[allow(clippy::struct_excessive_bools)]
pub struct LspCommand {
/// Path to the `pyproject.toml` or `ruff.toml` file to use for configuration.
#[arg(long, conflicts_with = "isolated")]
pub config: Option<PathBuf>,
/// Ignore all configuration files.
#[arg(long, conflicts_with = "config", help_heading = "Miscellaneous")]
pub isolated: bool,
/// Respect file exclusions via `.gitignore` and other standard ignore files.
#[arg(
long,
overrides_with("no_respect_gitignore"),
help_heading = "File selection"
)]
respect_gitignore: bool,
#[clap(long, overrides_with("respect_gitignore"), hide = true)]
no_respect_gitignore: bool,

/// Enable preview mode; checks will include unstable rules and fixes.
#[arg(long, overrides_with("no_preview"), hide = true)]
preview: bool,
#[clap(long, overrides_with("preview"), hide = true)]
no_preview: bool,
}

#[derive(Debug, Clone, Copy, clap::ValueEnum)]
pub enum HelpFormat {
Text,
Expand Down Expand Up @@ -565,7 +597,6 @@ pub struct CheckArguments {

/// CLI settings that are distinct from configuration (commands, lists of files,
/// etc.).
#[allow(clippy::struct_excessive_bools)]
pub struct FormatArguments {
pub check: bool,
pub config: Option<PathBuf>,
Expand All @@ -574,6 +605,11 @@ pub struct FormatArguments {
pub stdin_filename: Option<PathBuf>,
}

pub struct LspArguments {
pub config: Option<PathBuf>,
pub isolated: bool,
}

/// CLI settings that function as configuration overrides.
#[derive(Clone, Default)]
#[allow(clippy::struct_excessive_bools)]
Expand Down
5 changes: 2 additions & 3 deletions crates/ruff_cli/src/commands/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ use ruff_linter::logging::LogLevel;
use ruff_linter::warn_user_once;
use ruff_python_ast::{PySourceType, SourceType};
use ruff_python_formatter::{format_module_source, FormatModuleError};
use ruff_workspace::resolver::python_files_in_path;
use ruff_workspace::resolver::{python_files_in_path, PyprojectConfig};
use ruff_workspace::FormatterSettings;

use crate::args::{CliOverrides, FormatArguments};
use crate::panic::{catch_unwind, PanicError};
use crate::resolve::resolve;
use crate::ExitStatus;

#[derive(Debug, Copy, Clone, is_macro::Is)]
Expand All @@ -38,7 +37,7 @@ pub(crate) fn format(
overrides: &CliOverrides,
log_level: LogLevel,
) -> Result<ExitStatus> {
let pyproject_config = resolve(
let pyproject_config = PyprojectConfig::resolve(
cli.isolated,
cli.config.as_deref(),
overrides,
Expand Down
5 changes: 2 additions & 3 deletions crates/ruff_cli/src/commands/format_stdin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,17 @@ use log::warn;

use ruff_python_ast::PySourceType;
use ruff_python_formatter::format_module_source;
use ruff_workspace::resolver::python_file_at_path;
use ruff_workspace::resolver::{python_file_at_path, PyprojectConfig};
use ruff_workspace::FormatterSettings;

use crate::args::{CliOverrides, FormatArguments};
use crate::commands::format::{FormatCommandError, FormatCommandResult, FormatMode};
use crate::resolve::resolve;
use crate::stdin::read_from_stdin;
use crate::ExitStatus;

/// Run the formatter over a single file, read from `stdin`.
pub(crate) fn format_stdin(cli: &FormatArguments, overrides: &CliOverrides) -> Result<ExitStatus> {
let pyproject_config = resolve(
let pyproject_config = PyprojectConfig::resolve(
cli.isolated,
cli.config.as_deref(),
overrides,
Expand Down
74 changes: 74 additions & 0 deletions crates/ruff_cli/src/commands/lsp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use anyhow::Result;
use tracing::metadata::Level;
use tracing::subscriber::Interest;
use tracing::Metadata;
use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::layer::{Context, Filter, SubscriberExt};
use tracing_subscriber::{Layer, Registry};
use tracing_tree::time::Uptime;

use ruff_linter::logging::LogLevel;

use crate::args::LspCommand;
use crate::ExitStatus;

/// Format a set of files, and return the exit status.
#[allow(clippy::needless_pass_by_value)]
pub(crate) fn lsp(_arguments: LspCommand, log_level: LogLevel) -> Result<ExitStatus> {
let ruff_level = if log_level == LogLevel::Verbose {
Level::TRACE
} else {
Level::DEBUG
};

let subscriber = Registry::default().with(
tracing_tree::HierarchicalLayer::default()
.with_indent_lines(true)
.with_indent_amount(2)
.with_bracketed_fields(true)
.with_targets(true)
.with_writer(|| Box::new(std::io::stderr()))
.with_timer(Uptime::default())
.with_filter(LoggingFilter { ruff_level }),
);

tracing::subscriber::set_global_default(subscriber)?;

ruff_lsp::stdio();

Ok(ExitStatus::Success)
}

struct LoggingFilter {
ruff_level: Level,
}

impl LoggingFilter {
fn is_enabled(&self, meta: &Metadata<'_>) -> bool {
let filter = if meta.target().starts_with("ruff") {
self.ruff_level
} else {
Level::INFO
};

meta.level() <= &filter
}
}

impl<S> Filter<S> for LoggingFilter {
fn enabled(&self, meta: &Metadata<'_>, _cx: &Context<'_, S>) -> bool {
self.is_enabled(meta)
}

fn callsite_enabled(&self, meta: &'static Metadata<'static>) -> Interest {
if self.is_enabled(meta) {
Interest::always()
} else {
Interest::never()
}
}

fn max_level_hint(&self) -> Option<LevelFilter> {
Some(LevelFilter::from_level(self.ruff_level))
}
}
1 change: 1 addition & 0 deletions crates/ruff_cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub(crate) mod config;
pub(crate) mod format;
pub(crate) mod format_stdin;
pub(crate) mod linter;
pub(crate) mod lsp;
pub(crate) mod rule;
pub(crate) mod show_files;
pub(crate) mod show_settings;
8 changes: 5 additions & 3 deletions crates/ruff_cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ use ruff_linter::logging::{set_up_logging, LogLevel};
use ruff_linter::settings::flags;
use ruff_linter::settings::types::SerializationFormat;
use ruff_linter::{fs, warn_user, warn_user_once};
use ruff_workspace::resolver::PyprojectConfig;
use ruff_workspace::Settings;

use crate::args::{Args, CheckCommand, Command, FormatCommand};
use crate::commands::lsp::lsp;
use crate::printer::{Flags as PrinterFlags, Printer};

pub mod args;
Expand All @@ -24,7 +26,6 @@ mod commands;
mod diagnostics;
mod panic;
mod printer;
pub mod resolve;
mod stdin;

#[derive(Copy, Clone)]
Expand Down Expand Up @@ -162,6 +163,7 @@ pub fn run(
}
Command::Check(args) => check(args, log_level),
Command::Format(args) => format(args, log_level),
Command::Lsp(args) => lsp(args, log_level),
}
}

Expand Down Expand Up @@ -193,7 +195,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {

// Construct the "default" settings. These are used when no `pyproject.toml`
// files are present, or files are injected from outside of the hierarchy.
let pyproject_config = resolve::resolve(
let pyproject_config = PyprojectConfig::resolve(
cli.isolated,
cli.config.as_deref(),
&overrides,
Expand Down Expand Up @@ -333,7 +335,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
};

if matches!(change_kind, ChangeKind::Configuration) {
pyproject_config = resolve::resolve(
pyproject_config = PyprojectConfig::resolve(
cli.isolated,
cli.config.as_deref(),
&overrides,
Expand Down
101 changes: 0 additions & 101 deletions crates/ruff_cli/src/resolve.rs

This file was deleted.

3 changes: 1 addition & 2 deletions crates/ruff_dev/src/format_dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;

use ruff_cli::args::{FormatCommand, LogLevelArgs};
use ruff_cli::resolve::resolve;
use ruff_formatter::{FormatError, LineWidth, PrintError};
use ruff_linter::logging::LogLevel;
use ruff_linter::settings::types::{FilePattern, FilePatternSet};
Expand All @@ -52,7 +51,7 @@ fn ruff_check_paths(
.get_matches_from(dirs);
let arguments: FormatCommand = FormatCommand::from_arg_matches(&args_matches)?;
let (cli, overrides) = arguments.partition();
let mut pyproject_config = resolve(
let mut pyproject_config = PyprojectConfig::resolve(
cli.isolated,
cli.config.as_deref(),
&overrides,
Expand Down
2 changes: 1 addition & 1 deletion crates/ruff_formatter/src/printer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl<'a> Printer<'a> {

/// Prints the passed in element as well as all its content,
/// starting at the specified indentation level
#[tracing::instrument(name = "Printer::print", skip_all)]
#[tracing::instrument(name = "Printer::print", skip_all, fields(options=?self.options))]
pub fn print_with_indent(
mut self,
document: &'a Document,
Expand Down
Loading

0 comments on commit 02c6ea2

Please sign in to comment.