diff --git a/README.md b/README.md index bc7301a..456dbce 100644 --- a/README.md +++ b/README.md @@ -20,27 +20,29 @@ An R language server, linter, and code formatter, written in Rust. Roughly aims to support the following language server features (some are experimental or in progress): -- **Code Navigation** - - Goto definition (🧪 experimental) - - Search current document (Ctrl + Shift + O *in VS Code*) - - Search global workspace (Ctrl + T *in VS Code*) - - Indexing of global symbols, S4 classes/generics/methods and R6 classes/methods +- **Navigation** + - Indexing of global variables, S4 and R6 classes/methods + - Search current document - Ctrl + Shift + O *in VS Code* + - Search global workspace - Ctrl + T *in VS Code* + - Go to definition *(🧪 experimental)* + - Find all references *(🧪 experimental)* - **Diagnostics** - Syntax errors (including missing or trailing commas) - - Basic linting rules (e.g. `<-` assignment and variable naming) - - Unused variables (🧪 experimental) + - Basic linting rules (e.g. using `<-` for assignment or consistent `snake_case` / `camelCase`) + - Warn about unused variables *(🧪 experimental)* + +- **Editing** + - Autocomplete locals and global variables + - Autocomplete variables from other packages *(⚠️ missing)* + - Rename local variables *(🧪 experimental)* + - Rename global variables *(⚠️ missing)* + - Signature help *(🔨 work in progress)* - **Formatting** - - Entire documents - - Selected ranges (🧪 experimental) - -- **Code Completion** - - Local symbols - - Global symbols - - Package symbols (⚠️ missing) - - Signature help (⚠️ missing) - + - Format entire documents + - Format selected code ranges *(🧪 experimental)* + ## Roughly CLI You can install the Roughly CLI by downloading a pre-built binary or by building from source. @@ -87,13 +89,9 @@ Roughly can also be used as a VS Code extension. ### From Marketplace (Recommended) -Install directly from VS Code: -- Open VS Code -- Press Ctrl+Shift+X to open Extensions -- Search for "roughly" -- Click "Install" on the extension by `felix-andreas` +[![](https://vsmarketplacebadges.dev/version-short/felix-andreas.roughly.svg)](https://marketplace.visualstudio.com/items?itemName=felix-andreas.roughly) -Or, install using the [VS Code Marketplace website](https://marketplace.visualstudio.com/items?itemName=felix-andreas.roughly). +Install the extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=felix-andreas.roughly). > [!NOTE] > The VS Code extension from the marketplace includes a bundled version of the Roughly CLI **only for Windows and Linux x64**. If you are using macOS or a different architecture, you will need to install the Roughly CLI manually. @@ -121,8 +119,8 @@ You can customize the Roughly extension in VS Code through the following setting { // Use a custom binary instead of the bundled one "roughly.path": "/path/to/roughly", - // Pass extra arguments to the language server - "roughly.args": ["server", "--extra", "arg"], + // Pass custom arguments; defaults to ["server"] + "roughly.args": ["server", "--verbose"], // Enable experimental features "roughly.experimentalFeatures": ["goto_definition", "range_formatting"], } @@ -135,8 +133,10 @@ You can customize the Roughly extension in VS Code through the following setting You can access Roughly-specific commands in VS Code via the Command Palette (Ctrl+Shift+P): -- **Roughly: Start/Stop/Restart Server** - **Roughly: Open logs** +- **Roughly: Start/Stop/Restart Server** +- **Roughly: Format workspace** (⚠️ missing) +- **Roughly: Show syntax tree** (⚠️ missing) ## RStudio Integration @@ -163,14 +163,14 @@ naming-style = "snake_case" # or "camelCase", omit to disable this lint entirely Roughly includes several experimental features that can be enabled in the VS Code extension settings or via the CLI: -| Name | Description | -| ------------------ | --------------------------------- | -| `all` | Enables all experimental features | -| `goto_definition` | Jump to symbol definitions | -| `goto_references` | Find all references to a symbol | -| `range_formatting` | Format selected code ranges | -| `rename` | Rename symbols | -| `unused` | Detect unused variables | +| Name | Description | +| ------------------ | -------------------------------- | +| `all` | Enable all experimental features | +| `goto_definition` | Jump to symbol definitions | +| `goto_references` | Find all references to a symbol | +| `range_formatting` | Format selected code ranges | +| `rename` | Rename symbols | +| `unused` | Warn about unused variables | ## Development diff --git a/editors/code/README.md b/editors/code/README.md index 1a9ea4a..f30784d 100644 --- a/editors/code/README.md +++ b/editors/code/README.md @@ -7,10 +7,30 @@ This extension provides support for the [R programming language](https://www.r-p ## Features -* Autocomplete -* Code Formatting -* Syntax Diagnostics -* Workspace Symbol Search +Roughly aims to support the following language server features (some are experimental or in progress): + +- **Navigation** + - Indexing of global variables, S4 and R6 classes/methods + - Search current document - Ctrl + Shift + O *in VS Code* + - Search global workspace - Ctrl + T *in VS Code* + - Go to definition *(🧪 experimental)* + - Find all references *(🧪 experimental)* + +- **Diagnostics** + - Syntax errors (including missing or trailing commas) + - Basic linting rules (e.g. using `<-` for assignment or consistent `snake_case` / `camelCase`) + - Warn about unused variables *(🧪 experimental)* + +- **Editing** + - Autocomplete locals and global variables + - Autocomplete variables from other packages *(⚠️ missing)* + - Rename local variables *(🧪 experimental)* + - Rename global variables *(⚠️ missing)* + - Signature help *(🔨 work in progress)* + +- **Formatting** + - Format entire documents + - Format selected code ranges *(🧪 experimental)* ## Usage @@ -24,8 +44,8 @@ You can customize the Roughly extension in VS Code through the following setting { // Use a custom binary instead of the bundled one "roughly.path": "/path/to/roughly", - // Pass extra arguments to the language server - "roughly.args": ["server", "--extra", "arg"], + // Pass custom arguments; defaults to ["server"] + "roughly.args": ["server", "--verbose"], // Enable experimental features "roughly.experimentalFeatures": ["goto_definition", "range_formatting"], } diff --git a/scripts/create_large_codebase.rs b/scripts/create_large_codebase.rs new file mode 100644 index 0000000..9df6344 --- /dev/null +++ b/scripts/create_large_codebase.rs @@ -0,0 +1,114 @@ +use std::{fs, io::Write, path::Path}; + +const CONSTANT: &str = " <- 12345"; + +const FUNCTION: &str = r#" + <- function(n) { + if (n <= 0) { + return(NULL) + } else if (n == 1) { + return(0) + } else if (n == 2) { + return(1) + } else { + return((n - 1) + (n - 2)) + } +} +"#; + +const S4_CLASS: &str = r#" +setClass("", + slots = c( + name = "character", + age = "numeric" + ), + prototype = list( + name = NA_character_, + age = NA_real_ + ) +) +"#; + +const S4_METHODS: &str = r#" +setGeneric("", function(x) standardGeneric("")) +setGeneric("<-", function(x, value) standardGeneric("<-")) + +setMethod("", "", function(x) x@) +setMethod("<-", "", function(x, value) { + x@name <- value + x +}) +"#; + +const R6_CLASS: &str = r#" + <- R6Class("", + public = list( + initialize = function(...) { + for (item in list(...)) { + self$add(item) + } + }, + add = function(x) { + private$queue <- c(private$queue, list(x)) + invisible(self) + }, + remove = function() { + if (private$length() == 0) return(NULL) + # Can use private$queue for explicit access + head <- private$queue[[1]] + private$queue <- private$queue[-1] + head + } + ), + private = list( + queue = list(), + length = function() base::length(private$queue) + ) +) +"#; +fn main() { + use std::{fs, path::Path}; + + let base_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../R-large-codebase"); + let r_dir = base_dir.join("R"); + + if r_dir.exists() { + fs::remove_dir_all(&r_dir).unwrap(); + } + + fs::create_dir_all(&r_dir).unwrap(); + + for file in (b'a'..=b'z').flat_map(|c| (0..4).map(move |n| format!("{}{}", c, n))) { + let code = [ + // Constants + ["ALPHA", "BETA", "GAMA"] + .map(|name| CONSTANT.replace("", &format!("{}.{}", file, name))), + // Functions + ["alpha", "beta", "gama"] + .map(|name| FUNCTION.replace("", &format!("{}.{}", file, name))), + // S4 Classes and Methods + ["Alpha", "Beta", "Gamma"].map(|name| { + let class_code = S4_CLASS.replace("", &format!("{}.{}", file, name)); + let methods_code = (0..3) + .map(|i| { + S4_METHODS + .replace("", &format!("{}.{}.method{}", file, name, i)) + .replace("", &format!("{}.{}", file, name)) + }) + .collect::>() + .join("\n"); + format!("{}\n{}", class_code, methods_code) + }), + // R6 Classes + ["AlphaR6", "BetaR6", "GammaR6"] + .map(|name| R6_CLASS.replace("", &format!("{}.{}", file, name))), + ] + .into_iter() + .flat_map(|group| group) + .collect::>() + .join("\n"); + + let file_path = r_dir.join(format!("{}.R", file)); + fs::write(file_path, code).expect("Failed to write file"); + } +}