Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ Cargo.lock
.tabnine/
vscode/
objectscript-lsp/objectscript-tests/local/
objectscript-lsp/documentation/
objectscript-lsp/documentation/code-changes-AI
16 changes: 4 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,12 @@ An [ObjectScript](https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Pa

# Introduction

This Zed extension uses the [tree-sitter-objectscript](https://github.com/intersystems/tree-sitter-objectscript) grammar to provide syntax highlighting and code injections for `.cls` files containing ObjectScript. Since ObjectScripts supports a number of embedded languages, you should install grammars for the following languages otherwise you may see areas that appear to lack syntax coloring.
This Zed extension uses the [tree-sitter-objectscript](https://github.com/intersystems/tree-sitter-objectscript) grammars and the `objectscript-lsp` crate (local to this repo) to provide syntax highlighting, code injections, and language support for `.cls`, `.mac`, `.rtn`, `.inc`, `.int` and `.xml` files containing ObjectScript. Install the following extensions below to get syntax highlighting for any code injected into objectscript that is `sql` or `html`.

- SQL
- HTML
- Python
- JavaScript
- CSS
- XML
- Markdown
- [SQL](https://zed.dev/extensions/sql)
- [HTML](https://zed.dev/extensions/html)

**NOTE**: The ObjectScript `.cls` syntax supports some sophisticated constructs and as such it can take 15-60 seconds for Zed's WASM machinery to build the parser before syntax coloring becomes available.

Currently this extension only provides syntax coloring support.
The current features supported in the `ObjectScript language server` are `goto_definition`, `goto_implementation`, `refactor`, and `diagnostics`. These features are described in detail in the `objectscript-lsp/documentation/features` folder.

## Reporting Issues

Expand Down Expand Up @@ -46,4 +39,3 @@ RUST_LOG = "language,extension=trace"

Cloning and the building a debug Zed with these `RUST_LOG` settings gives fairly detailed log output including diagnosing
bad `.scm` rules.

12 changes: 12 additions & 0 deletions documentation/dev-extension-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Using the Zed ObjectScript Extension (Dev Extension)
The Dev Extension allows you to reference the most recent updates from this repo before they get officially merged into the `zed-extensions` repo.

The official extension is here: [objectscript extension](https://zed.dev/extensions/objectscript)

**STEPS**
`PREREQS`: Make sure you have the Zed editor downloaded and the `zed-objectscript` repo locally.

1. Open Zed Editor
2. Go to command Palette (Command Shift P) -> `zed: Extensions`
3. Click Install Dev Extension
4. Point it to the `zed-objectscript` folder on your local device.
64 changes: 46 additions & 18 deletions languages/xml/injections.scm
Original file line number Diff line number Diff line change
@@ -1,18 +1,46 @@
(
element
(STag (Name) @_start_tag)
(content (CDSect (CData) @injection.content))
(ETag (Name) @_end_tag)
(#eq? @_start_tag "Implementation")
(#eq? @_end_tag "Implementation")
(#set! injection.language "objectscript")
)
(
element
(STag (Name) @_start_tag)
(content (CharData) @injection.content)
(ETag (Name) @_end_tag)
(#eq? @_start_tag "Implementation")
(#eq? @_end_tag "Implementation")
(#set! injection.language "objectscript")
)
((Comment) @injection.content
(#set! injection.language "comment"))

((element
(STag
(Name) @_name)
(content) @injection.content)
(#eq? @_name "style")
(#set! injection.combined)
(#set! injection.include-children)
(#set! injection.language "css"))

((element
(STag
(Name) @_name)
(content) @injection.content)
(#eq? @_name "script")
(#set! injection.combined)
(#set! injection.include-children)
(#set! injection.language "javascript"))

((element
(STag
(Name) @_name)
(content) @injection.content)
(#eq? @_name "pma:table")
(#set! injection.combined)
(#set! injection.include-children)
(#set! injection.language "sql"))

(element
(STag
(Name) @_name)
(content
(CDSect
(CData) @injection.content))
(#eq? @_name "Implementation")
(#set! injection.language "objectscript"))

(element
(STag
(Name) @_name)
(content
(CharData) @injection.content)
(#eq? @_name "Implementation")
(#set! injection.language "objectscript"))
683 changes: 0 additions & 683 deletions objectscript-lsp/docs/agent-change-documentation.md

This file was deleted.

51 changes: 51 additions & 0 deletions objectscript-lsp/documentation/features/diagnostics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Diagnostics Feature

## Overview

The diagnostics feature reports syntax errors in ObjectScript and XML files. It uses tree-sitter parse trees to detect error nodes and reports them as LSP diagnostics with severity `ERROR`.

## Supported File Types

| File Type | Diagnostics Provided |
|---|---|
| Class (`.cls`) | ObjectScript syntax errors |
| Routine (`.mac`, `.int`, `.rtn`, `.inc`) | ObjectScript syntax errors |
| XML (`.xml`) | XML syntax errors + ObjectScript errors in `<Implementation>` blocks |

## Diagnostic Types

### ObjectScript Syntax Errors

Reported when tree-sitter produces error or missing nodes in the parse tree. Each error node becomes a diagnostic at that node's source range.

**Context-aware messages** — when the error occurs in a recognizable context, a more helpful message is produced:

| Context | Message |
|---|---|
| After `Set` keyword with no target | "Expected a variable name, got {text}" |
| After `set_target` with no `=` | "Expected '=' or another variable name..." |
| After `=` in `Set` with no expression | "Expected an expression, {text} is not a valid expression." |
| After expression in `Set` | "Unexpected, {text} after an expression. Expected a binary operator or end of SET command" |
| All other cases | "Syntax Error: Unexpected {text}" |

### XML Syntax Errors

For XML files, tree-sitter XML error nodes produce diagnostics with the message format: `"XML syntax error: Unexpected {text}"`.

### Mixed-Language Diagnostics (XML + ObjectScript)

For XML files that contain ObjectScript code inside `<Implementation>` CDATA blocks, the LSP performs a second diagnostic pass:

1. Finds all `<Implementation>` elements in the XML tree
2. Extracts the CDATA or CharData content from each
3. Parses each extracted region as ObjectScript using an independent parser
4. Reports any ObjectScript syntax errors found within those regions

This provides syntax checking for ObjectScript code that is embedded within XML class export files.

## Behavior

- Diagnostics are computed on-demand via the `textDocument/diagnostic` pull model (not push-based `textDocument/publishDiagnostics`)
- Each diagnostic request returns a full report for the requested document
- Inter-file dependencies are not tracked (a change in one file does not trigger diagnostics in another)
- Workspace-level diagnostics are not supported (only per-document)
84 changes: 84 additions & 0 deletions objectscript-lsp/documentation/features/goto-def.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Goto-Definition Feature

## Overview

The goto-definition feature resolves the definition site of a symbol under the cursor. It handles classes, methods (instance, class, procedures, subroutines, relative dot methods, and oref-chained), variables (private and public), superclass navigation, and numeric line offsets.

## Supported Symbols

### Classes

| Cursor position | Navigation target |
|---|---|
| Class name at its own definition (`Class MyClass Extends Super`) | The superclass(es) it extends |
| Class name used as a reference (`##class(Demo.Person)`) | The class definition file of that class name |
| Routine name in a line reference (`^RoutineName`) | The routine file |

### Methods

| Cursor position | Navigation target |
|---|---|
| Method name at its definition site (`Method Save()`) | The superclass method it overrides (if any) |
| Relative dot method call (`..MethodName()`) | The method definition in the same class |
| Class method call (`##class(Cls).MethodName()`) | The method definition in the referenced class |
| Same-file label call (`Do Label`, `Write Label`) | The label/subroutine definition in the current file |
| Cross-routine label call (`Do Label^Routine`, `$$Label^Routine`) | The label definition in the referenced routine |
| Label with offset (`Do Label+3^Routine`) | The method definition, offset by N lines |
| Oref method call, cursor on method (`obj.Method()`) | The method definition in the resolved class of `obj` |
| Oref method from `%New` (`##class(Cls).%New().Method()`) | The method definition in `Cls` |

### Variables

| Cursor position | Navigation target |
|---|---|
| Local variable reference | The closest preceding definition of that variable in the same scope (or parent scopes) |
| Public variable (non-ProcedureBlock or declared public) | The closest preceding definition, potentially across calling methods via the dependency graph |
| Oref variable, cursor on variable name (`obj` in `obj.Method()`) | The assignment site where the oref was created |
| Global variable (`^GlobalName`) | Same resolution as local variables (scope-based lookup) |

### Line Offsets

| Cursor position | Navigation target |
|---|---|
| Numeric literal in a tag call (`3` in `Do Label+3`) | The line N rows below the current position |

## Variable Resolution Rules

Variable resolution picks the **closest definition that appears before the reference**:

- If multiple `Set` commands assign the same variable in the same scope, goto-def resolves to the one nearest (but still before) the cursor.
- If no definition exists in the current scope, parent scopes and ancestor scopes are checked.
- For public variables, the DependencyGraph traces callers (via BFS) and finds the definition in the shallowest ancestor method that defines the variable before the call site.

**Example:**
```objectscript
Set x = 2
Set y = 3
Set x = 3
Write x ; goto-def on x here → resolves to "Set x = 3"
```

## Oref Resolution Rules

When resolving `obj.Method()`, the LSP must determine what class `obj` is an instance of:

1. Finds the assignment of `obj` (e.g., `Set obj = ##class(Demo.Person).%New()`)
2. Extracts the class from the `%New()` call
3. Looks up `Method` in that class's method definitions

If the variable is public, the same DependencyGraph-based ancestor traversal is used to find the assignment across method boundaries.

## Scopes

Scopes that create boundaries for variable resolution:
- Classes
- Methods
- Subroutines / Procedures
- Conditional blocks (`If`/`ElseIf`/`Else`)

## Inheritance Rules for Superclass Navigation

When navigating from a method definition to its superclass override, the LSP uses the OverrideIndex which respects ObjectScript's inheritance rules: if a class inherits from multiple superclasses that define the same method, the override resolution follows the language's defined precedence order.

## TODO
I still need to use `kill` and `new` statements in my analysis of what variable definitions are actually valid from a given method. If a `kill` statement appears, any definitions that came before that should be nullified.
27 changes: 27 additions & 0 deletions objectscript-lsp/documentation/features/goto-implementation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Goto-Implementation Feature

## Overview

The goto-implementation feature navigates from a class or method definition to its **subclass overrides**. This is the inverse of goto-definition's superclass navigation — where goto-def goes "up" the inheritance chain, goto-implementation goes "down" to find subclasses and overriding methods.

## Supported Symbols

### Classes

| Cursor position | Navigation target |
|---|---|
| Class name at its own definition (`Class MyClass`) | All subclasses that extend this class |
| Class name used as a reference (`##class(MyClass)`) | All subclasses that extend the referenced class |

### Methods

| Cursor position | Navigation target |
|---|---|
| Method name at its definition site (`Method Save()`) | All subclass methods that override this method |
| Method name in a class method call (`##class(Cls).Method()`) | All subclass methods that override the referenced method |

## Behavior

- If exactly one implementation is found, the editor navigates directly to it.
- If multiple implementations are found, the editor presents a picker with all locations.
- If no implementations are found, a warning message is shown: "No implementations were found for the given symbol."
Loading