mui-lsp 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 990948dead05098d8add9c4fc12c55470b8361fcafc8ca8de025be882f81d0b8
4
- data.tar.gz: 89e3a3c9c0bc688342fcfde30576b94d186ec1207a178af279eed1df73cd1076
3
+ metadata.gz: 263fd9cae12708ea5be41993083794357068d8af592bc9b7684f650cd9eb094d
4
+ data.tar.gz: 14d542c5978a50e0095acd951a418e43445208a7907024df7eb4dff8ead2e499
5
5
  SHA512:
6
- metadata.gz: 05e02edfd2e6658e488d7b9b7f04dd97f9ec08aec3d7025ece92913a67e7a4ecb8dd7270b5cc2dc1e91622fb878e12b61452b150dcce3d78c61bd3c6f8130672
7
- data.tar.gz: 2ba900393380934caa9392790791b19910ba2078db4e5a3a8851a8c64d983e12eb5acf1b18e3093c3aadfaa17777fd35f1b95c9741e24f79a467d35f50fa0808
6
+ metadata.gz: 488392ecc54c123a1a558def0e6b8ec326f85252f0ab95bb2dc97fc40f5a864e43a60563578d0e3b817207ae5122bcb1f5350a0cb884db5ea01549a9e42bfcf1
7
+ data.tar.gz: 8fd6da70ce1e5640e35f72d3d1239d0ec2d5fb76a3e5791a8b406f0efb1b3a3369a16bed112b1ba153d8ec9e96141fdcc0e6a3483470f2faeed10951864b6e26
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2025-12-11 11:19:34 UTC using RuboCop version 1.81.7.
3
+ # on 2025-12-26 06:52:41 UTC using RuboCop version 1.81.7.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -12,36 +12,54 @@ Lint/DuplicateBranch:
12
12
  Exclude:
13
13
  - 'lib/mui/lsp/highlighters/diagnostic_highlighter.rb'
14
14
 
15
- # Offense count: 16
15
+ # Offense count: 1
16
+ # Configuration parameters: AllowComments.
17
+ Lint/EmptyClass:
18
+ Exclude:
19
+ - 'test/mui/lsp/handlers/test_completion.rb'
20
+
21
+ # Offense count: 25
16
22
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
17
23
  Metrics/AbcSize:
18
- Max: 44
24
+ Max: 46
19
25
 
20
- # Offense count: 6
26
+ # Offense count: 8
21
27
  # Configuration parameters: CountComments, CountAsOne.
22
28
  Metrics/ClassLength:
23
- Max: 361
29
+ Max: 435
24
30
 
25
- # Offense count: 7
31
+ # Offense count: 8
26
32
  # Configuration parameters: AllowedMethods, AllowedPatterns.
27
33
  Metrics/CyclomaticComplexity:
28
34
  Max: 26
29
35
 
30
- # Offense count: 42
36
+ # Offense count: 83
31
37
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
32
38
  Metrics/MethodLength:
33
- Max: 61
39
+ Max: 56
34
40
 
35
41
  # Offense count: 4
36
42
  # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
37
43
  Metrics/ParameterLists:
38
44
  Max: 6
39
45
 
40
- # Offense count: 6
46
+ # Offense count: 5
41
47
  # Configuration parameters: AllowedMethods, AllowedPatterns.
42
48
  Metrics/PerceivedComplexity:
43
49
  Max: 14
44
50
 
51
+ # Offense count: 1
52
+ Naming/AccessorMethodName:
53
+ Exclude:
54
+ - 'lib/mui/lsp/handlers/completion.rb'
55
+
56
+ # Offense count: 4
57
+ # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
58
+ # AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
59
+ Naming/MethodParameterName:
60
+ Exclude:
61
+ - 'test/fixtures/sample.rb'
62
+
45
63
  # Offense count: 2
46
64
  # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
47
65
  # AllowedMethods: call
@@ -65,7 +83,7 @@ Style/IfUnlessModifier:
65
83
  Exclude:
66
84
  - 'lib/mui/lsp/json_rpc_io.rb'
67
85
 
68
- # Offense count: 1
86
+ # Offense count: 4
69
87
  # This cop supports safe autocorrection (--autocorrect).
70
88
  # Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
71
89
  # URISchemes: http, https
data/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.3.0] - 2025-12-26
4
+
5
+ ### Added
6
+ - Multiple LSP result merging:
7
+ - Definition, References, and Type Definition now query all matching LSP servers
8
+ - Results from all servers are merged and deduplicated
9
+ - Enables showing both Ruby source and RBS type definitions together
10
+ - Steep pre-configured server:
11
+ - `use :steep` in `Mui.lsp` block to enable
12
+ - Requires `Steepfile` in project root
13
+ - Supports `.rb` and `.rbs` files
14
+ - Ruby/RBS file toggle (`<Space>tf`):
15
+ - In Ruby files: jumps to corresponding RBS file in `sig/` directory
16
+ - In RBS files: jumps to corresponding Ruby file in `lib/` directory
17
+ - Searches multiple path patterns (e.g., `lib/mui/config.rb` → `sig/mui/config.rbs`)
18
+ - For non-Ruby files: uses LSP `textDocument/typeDefinition` as before
19
+ - Type definition support (`textDocument/typeDefinition`):
20
+ - `:LspTypeDefinition` command to jump to type definition
21
+ - `<Space>tf` keymap for type definition
22
+ - Works with TypeProf, Sorbet, Steep and other Ruby type checkers
23
+ - Uses same picker UI as Definition when multiple candidates found
24
+ - TypeProf pre-configured server:
25
+ - `use :typeprof` in `Mui.lsp` block to enable
26
+ - Requires `typeprof.conf.jsonc` in project root (run `typeprof --init` to create)
27
+ - Format support (`textDocument/formatting`):
28
+ - `:LspFormat` command to format current file
29
+ - `<Space>ff` keymap for formatting
30
+ - Works with RuboCop LSP and other formatters
31
+ - Location picker for Definition and References:
32
+ - When multiple definitions or references are found, opens a scratch buffer picker
33
+ - `j`/`k` - Navigate up/down (native cursor movement)
34
+ - `\` + `Enter` - Open selected location in current window
35
+ - `Ctrl+t` - Open selected location in new tab
36
+ - `\q` / `\` + `Esc` - Close picker
37
+
38
+ ### Fixed
39
+ - Type definition now checks `typeDefinitionProvider` capability before sending requests
40
+ - Prevents sending requests to servers that don't support type definition (e.g., Solargraph)
41
+ - Shows helpful message when no server supports type definition
42
+
43
+ ### Changed
44
+ - Keymaps changed from leader key (`\`) to `<Space>` prefix:
45
+ - `<Space>df` - Go to definition
46
+ - `<Space>rf` - Find references
47
+ - `<Space>hf` - Show hover information
48
+ - `<Space>cf` - Show completion
49
+ - `<Space>ef` - Show diagnostic at cursor
50
+ - Removed manual `@leader_pending` state management in favor of Mui's native multi-key sequence support
51
+
52
+ ## [0.2.0] - 2025-12-12
53
+
54
+ ### Added
55
+ - Insert mode LSP completion support:
56
+ - Auto-trigger completion after `.`, `@`, and `::` characters via `InsertCompletion` autocmd
57
+ - Uses `textEdit` for precise text replacement (e.g., `@user` replaces properly)
58
+ - `force_reopen` ensures LSP has latest buffer content before completion
59
+ - Completion items include `label`, `kind`, `detail`, `documentation`, and `text_edit`
60
+ - `Ctrl+Space` keymap in Insert mode to manually trigger LSP completion
61
+
3
62
  ## [0.1.1] - 2025-12-11
4
63
 
5
64
  ### Changed
data/README.md CHANGED
@@ -4,10 +4,12 @@ LSP (Language Server Protocol) plugin for [Mui](https://github.com/S-H-GAMELINKS
4
4
 
5
5
  ## Features
6
6
 
7
- - **Hover**: Show documentation for symbol under cursor (`K` or `\h` or `:LspHover`)
8
- - **Go to Definition**: Jump to symbol definition (`\d` or `:LspDefinition`)
9
- - **Find References**: Show all references to symbol (`\r` or `:LspReferences`)
10
- - **Completion**: Get code completion suggestions (`\c` or `:LspCompletion`)
7
+ - **Hover**: Show documentation for symbol under cursor (`K` or `<Space>hf` or `:LspHover`)
8
+ - **Go to Definition**: Jump to symbol definition (`<Space>df` or `:LspDefinition`)
9
+ - **Go to Type Definition**: Jump to type definition or toggle between Ruby/RBS files (`<Space>tf` or `:LspTypeDefinition`)
10
+ - **Find References**: Show all references to symbol (`<Space>rf` or `:LspReferences`)
11
+ - **Completion**: Get code completion suggestions (`<Space>cf` or `:LspCompletion`)
12
+ - **Format**: Format current file with LSP server (`<Space>ff` or `:LspFormat`)
11
13
  - **Diagnostics**: Display errors and warnings from LSP server (`:LspDiagnostics`)
12
14
 
13
15
  ## Supported Language Servers
@@ -18,6 +20,8 @@ Pre-configured servers for Ruby:
18
20
  - **ruby-lsp** - Shopify's Ruby language server
19
21
  - **Kanayago** - Realtime Ruby Syntax Check server
20
22
  - **RuboCop** (LSP mode) - Ruby linter with LSP support
23
+ - **TypeProf** - Ruby type analysis and inference
24
+ - **Steep** - Ruby type checker with RBS support
21
25
 
22
26
  Custom servers can be configured for other languages.
23
27
 
@@ -59,6 +63,42 @@ Available pre-configured servers:
59
63
  - `:ruby_lsp` - ruby-lsp (Shopify's Ruby LSP)
60
64
  - `:rubocop` - RuboCop in LSP mode
61
65
  - `:kanayago` - Kanayago (Japanese Ruby LSP)
66
+ - `:typeprof` - TypeProf (Ruby type analysis)
67
+ - `:steep` - Steep (Ruby type checker with RBS)
68
+
69
+ ### TypeProf Setup
70
+
71
+ TypeProf requires a configuration file in your project root. Run:
72
+
73
+ ```bash
74
+ typeprof --init
75
+ ```
76
+
77
+ This creates `typeprof.conf.jsonc` with default settings:
78
+
79
+ ```jsonc
80
+ {
81
+ "typeprof_version": "experimental",
82
+ "rbs_dir": "sig/",
83
+ "analysis_unit_dirs": ["lib"]
84
+ }
85
+ ```
86
+
87
+ TypeProf will only analyze files in the directories specified in `analysis_unit_dirs`. Without this configuration file, TypeProf will not track documents and type definition features will not work.
88
+
89
+ ### Steep Setup
90
+
91
+ Steep requires a `Steepfile` in your project root. Create one with:
92
+
93
+ ```ruby
94
+ # Steepfile
95
+ target :lib do
96
+ signature "sig"
97
+ check "lib"
98
+ end
99
+ ```
100
+
101
+ Place your RBS type definitions in the `sig/` directory.
62
102
 
63
103
  ### Custom Server Configuration
64
104
 
@@ -126,27 +166,40 @@ To manually start a server:
126
166
  | `:LspStatus` | Show running and registered servers |
127
167
  | `:LspHover` | Show hover information |
128
168
  | `:LspDefinition` | Go to definition |
169
+ | `:LspTypeDefinition` | Go to type definition |
129
170
  | `:LspReferences` | Find all references |
130
171
  | `:LspCompletion` | Show completion menu |
131
172
  | `:LspDiagnostics` | Show diagnostics for current file |
132
173
  | `:LspDiagnosticShow` | Show diagnostic at cursor in floating window |
174
+ | `:LspFormat` | Format current file |
133
175
  | `:LspLog` | Show LSP server logs in a buffer |
134
176
  | `:LspDebug` | Show debug information |
135
177
  | `:LspOpen` | Manually notify LSP server about current file |
136
178
 
137
179
  ### Keymaps
138
180
 
139
- Leader key is `\` (backslash).
140
-
141
181
  | Key | Mode | Description |
142
182
  |-----|------|-------------|
143
183
  | `K` | Normal | Show hover information (in floating window) |
144
- | `\h` | Normal | Show hover information (alternative) |
145
- | `\d` | Normal | Go to definition |
146
- | `\r` | Normal | Find references |
147
- | `\c` | Normal | Show completion |
148
- | `\e` | Normal | Show diagnostic at cursor (in floating window) |
149
- | `Esc` | Normal | Cancel leader pending state / Close floating window |
184
+ | `<Space>df` | Normal | Go to definition |
185
+ | `<Space>tf` | Normal | Go to type definition (Ruby: toggle .rb/.rbs) |
186
+ | `<Space>rf` | Normal | Find references |
187
+ | `<Space>hf` | Normal | Show hover information (alternative to K) |
188
+ | `<Space>cf` | Normal | Show completion |
189
+ | `<Space>ef` | Normal | Show diagnostic at cursor (in floating window) |
190
+ | `<Space>ff` | Normal | Format current file |
191
+ | `Esc` | Normal | Close floating window / picker |
192
+
193
+ #### Location Picker (for Definition/References with multiple candidates)
194
+
195
+ When multiple definitions or references are found, a picker buffer opens. Use standard Vim navigation:
196
+
197
+ | Key | Description |
198
+ |-----|-------------|
199
+ | `j`/`k` | Navigate up/down (native cursor movement) |
200
+ | `\` + `Enter` | Open selected location in current window |
201
+ | `Ctrl+t` | Open selected location in new tab |
202
+ | `\q` / `\` + `Esc` | Close picker |
150
203
 
151
204
  ## Architecture
152
205
 
@@ -162,9 +215,11 @@ mui-lsp/
162
215
  base.rb # Base handler class
163
216
  hover.rb # Hover response handler
164
217
  definition.rb # Definition response handler
218
+ type_definition.rb # Type definition response handler
165
219
  references.rb # References response handler
166
220
  diagnostics.rb # Diagnostics notification handler
167
221
  completion.rb # Completion response handler
222
+ formatting.rb # Formatting response handler
168
223
  json_rpc_io.rb # JSON-RPC 2.0 over stdio
169
224
  request_manager.rb # Request ID and callback management
170
225
  server_config.rb # Server configuration presets
@@ -104,6 +104,13 @@ module Mui
104
104
  }, &callback)
105
105
  end
106
106
 
107
+ def type_definition(uri:, line:, character:, &callback)
108
+ request("textDocument/typeDefinition", {
109
+ textDocument: { uri: uri },
110
+ position: { line: line, character: character }
111
+ }, &callback)
112
+ end
113
+
107
114
  def references(uri:, line:, character:, include_declaration: true, &callback)
108
115
  request("textDocument/references", {
109
116
  textDocument: { uri: uri },
@@ -119,6 +126,16 @@ module Mui
119
126
  }, &callback)
120
127
  end
121
128
 
129
+ def formatting(uri:, tab_size: 2, insert_spaces: true, &callback)
130
+ request("textDocument/formatting", {
131
+ textDocument: { uri: uri },
132
+ options: {
133
+ tabSize: tab_size,
134
+ insertSpaces: insert_spaces
135
+ }
136
+ }, &callback)
137
+ end
138
+
122
139
  def did_open(uri:, language_id:, version:, text:)
123
140
  notify("textDocument/didOpen", {
124
141
  textDocument: {
@@ -270,7 +287,13 @@ module Mui
270
287
  definition: {
271
288
  linkSupport: false
272
289
  },
290
+ typeDefinition: {
291
+ linkSupport: false
292
+ },
273
293
  references: {},
294
+ formatting: {
295
+ dynamicRegistration: false
296
+ },
274
297
  publishDiagnostics: {
275
298
  relatedInformation: true
276
299
  },
@@ -84,8 +84,30 @@ module Mui
84
84
  end
85
85
 
86
86
  def display_completions(items)
87
- # For now, show first few items in message
88
- # TODO: Integrate with Mui's popup menu or completion system
87
+ # Use Mui's insert completion API if available
88
+ if @editor.respond_to?(:start_insert_completion)
89
+ prefix = get_current_prefix
90
+ @editor.start_insert_completion(items, prefix:)
91
+ else
92
+ # Fallback: show message
93
+ show_message_fallback(items)
94
+ end
95
+ end
96
+
97
+ def get_current_prefix
98
+ window = @editor.window
99
+ buffer = window.buffer
100
+ line = buffer.line(window.cursor_row)
101
+ col = window.cursor_col
102
+
103
+ # Find word start
104
+ start_col = col
105
+ start_col -= 1 while start_col.positive? && line[start_col - 1] =~ /\w/
106
+
107
+ line[start_col...col] || ""
108
+ end
109
+
110
+ def show_message_fallback(items)
89
111
  count = items.length
90
112
 
91
113
  # Build a summary message
@@ -94,13 +116,6 @@ module Mui
94
116
  summary += ", ..." if count > 3
95
117
 
96
118
  @editor.message = "#{count} completion#{"s" unless count == 1}: #{summary}"
97
-
98
- # Store items for potential insertion
99
- store_completions(items)
100
- end
101
-
102
- def store_completions(items)
103
- @editor.instance_variable_set(:@lsp_completions, items)
104
119
  end
105
120
 
106
121
  def kind_to_string(kind)
@@ -83,15 +83,22 @@ module Mui
83
83
  end
84
84
 
85
85
  def show_location_list(locations)
86
- # Show a list of locations for the user to choose from
87
- items = locations.map do |loc|
86
+ # Store locations for picker navigation
87
+ @editor.instance_variable_set(:@lsp_picker_locations, locations)
88
+ @editor.instance_variable_set(:@lsp_picker_type, :definition)
89
+
90
+ # Build picker content
91
+ lines = []
92
+ locations.each_with_index do |loc, idx|
88
93
  file_path = loc.file_path || loc.uri
89
- line = loc.range.start.line + 1
90
- "#{file_path}:#{line}"
94
+ display_path = File.basename(file_path.to_s)
95
+ line_num = loc.range.start.line + 1
96
+ lines << "#{idx + 1}. #{display_path}:#{line_num}"
91
97
  end
92
98
 
93
- @editor.message = "Found #{locations.length} definitions: #{items.first}..."
94
- # TODO: Integrate with quickfix list or popup menu when available
99
+ # Open scratch buffer for picker
100
+ content = "Definitions (\\Enter:open, Ctrl+t:tab, \\q:close)\n\n#{lines.join("\n")}"
101
+ @editor.open_scratch_buffer("[LSP Picker]", content)
95
102
  end
96
103
  end
97
104
  end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mui
4
+ module Lsp
5
+ module Handlers
6
+ # Handler for textDocument/formatting responses
7
+ class Formatting < Base
8
+ protected
9
+
10
+ def handle_result(result)
11
+ return handle_empty unless result.is_a?(Array) && !result.empty?
12
+
13
+ apply_text_edits(result)
14
+ end
15
+
16
+ def handle_empty
17
+ @editor.message = "No formatting changes"
18
+ end
19
+
20
+ private
21
+
22
+ def apply_text_edits(edits)
23
+ buffer = @editor.buffer
24
+ return @editor.message = "No buffer" unless buffer
25
+
26
+ # Sort edits in reverse order (bottom to top) to avoid position shifts
27
+ sorted_edits = edits.sort_by do |edit|
28
+ range = edit["range"]
29
+ start_line = range["start"]["line"]
30
+ start_char = range["start"]["character"]
31
+ [-start_line, -start_char]
32
+ end
33
+
34
+ # Apply each edit
35
+ changes_count = 0
36
+ sorted_edits.each do |edit|
37
+ apply_single_edit(buffer, edit)
38
+ changes_count += 1
39
+ end
40
+
41
+ @editor.message = "Formatted (#{changes_count} change#{"s" unless changes_count == 1})"
42
+ end
43
+
44
+ def apply_single_edit(buffer, edit)
45
+ range = edit["range"]
46
+ new_text = edit["newText"]
47
+
48
+ start_line = range["start"]["line"]
49
+ start_char = range["start"]["character"]
50
+ end_line = range["end"]["line"]
51
+ end_char = range["end"]["character"]
52
+
53
+ # Get current lines
54
+ lines = buffer.lines
55
+
56
+ # Build new content
57
+ # Get text before the edit range
58
+ before_text = if start_line < lines.length
59
+ line = lines[start_line] || ""
60
+ line[0, start_char] || ""
61
+ else
62
+ ""
63
+ end
64
+
65
+ # Get text after the edit range
66
+ after_text = if end_line < lines.length
67
+ line = lines[end_line] || ""
68
+ line[end_char..] || ""
69
+ else
70
+ ""
71
+ end
72
+
73
+ # Split new_text into lines
74
+ new_lines = new_text.split("\n", -1)
75
+
76
+ new_lines = [""] if new_lines.empty?
77
+
78
+ # Combine before_text with first new line
79
+ new_lines[0] = before_text + new_lines[0]
80
+
81
+ # Combine last new line with after_text
82
+ new_lines[-1] = new_lines[-1] + after_text
83
+
84
+ # Replace lines in buffer
85
+ # Delete old lines
86
+ delete_count = end_line - start_line + 1
87
+ delete_count.times do
88
+ buffer.delete_line(start_line) if start_line < buffer.lines.length
89
+ end
90
+
91
+ # Insert new lines
92
+ new_lines.each_with_index do |line, idx|
93
+ buffer.insert_line(start_line + idx, line)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -11,7 +11,12 @@ module Mui
11
11
  return handle_empty unless result.is_a?(Array) && !result.empty?
12
12
 
13
13
  locations = result.map { |loc| Protocol::Location.from_hash(loc) }
14
- show_references(locations)
14
+
15
+ if locations.length == 1
16
+ jump_to_location(locations.first)
17
+ else
18
+ show_location_list(locations)
19
+ end
15
20
  end
16
21
 
17
22
  def handle_empty
@@ -20,44 +25,52 @@ module Mui
20
25
 
21
26
  private
22
27
 
23
- def show_references(locations)
24
- count = locations.length
25
-
26
- # Build message with first few references
27
- lines = ["Found #{count} reference#{"s" unless count == 1}"]
28
-
29
- # Group by file for display
30
- by_file = locations.group_by(&:file_path)
31
-
32
- # Display first few references
33
- displayed = 0
34
- max_display = 3
35
-
36
- by_file.each do |file_path, file_locations|
37
- break if displayed >= max_display
28
+ def jump_to_location(location)
29
+ file_path = location.file_path
30
+ unless file_path
31
+ @editor.message = "Cannot open: #{location.uri}"
32
+ return
33
+ end
38
34
 
39
- file_locations.each do |loc|
40
- break if displayed >= max_display
35
+ line = location.range.start.line
36
+ character = location.range.start.character
41
37
 
42
- line = loc.range.start.line + 1
43
- lines << " #{file_path || loc.uri}:#{line}"
44
- displayed += 1
45
- end
38
+ # Open the file in current window
39
+ current_buffer = @editor.buffer
40
+ if current_buffer.file_path != file_path
41
+ new_buffer = Mui::Buffer.new
42
+ new_buffer.load(file_path)
43
+ @editor.window.buffer = new_buffer
46
44
  end
47
45
 
48
- lines << " ... and #{count - max_display} more" if count > max_display
46
+ # Jump to position
47
+ window = @editor.window
48
+ return unless window
49
49
 
50
- @editor.message = lines.first
50
+ window.cursor_row = line
51
+ window.cursor_col = character
52
+ window.ensure_cursor_visible
51
53
 
52
- # TODO: Integrate with quickfix list when available
53
- # Store references for navigation
54
- store_references(locations)
54
+ @editor.message = "#{File.basename(file_path)}:#{line + 1}"
55
55
  end
56
56
 
57
- def store_references(locations)
58
- # Store references for potential :cnext/:cprev navigation
59
- # This could be integrated with Mui's quickfix system if available
60
- @editor.instance_variable_set(:@lsp_references, locations)
57
+ def show_location_list(locations)
58
+ # Store locations for picker navigation
59
+ @editor.instance_variable_set(:@lsp_picker_locations, locations)
60
+ @editor.instance_variable_set(:@lsp_picker_type, :references)
61
+
62
+ # Build picker content
63
+ lines = []
64
+ locations.each_with_index do |loc, idx|
65
+ file_path = loc.file_path || loc.uri
66
+ display_path = File.basename(file_path.to_s)
67
+ line_num = loc.range.start.line + 1
68
+ lines << "#{idx + 1}. #{display_path}:#{line_num}"
69
+ end
70
+
71
+ # Open scratch buffer for picker
72
+ content = "References (#{locations.length} found) (\\Enter:open, Ctrl+t:tab, \\q:close)\n\n#{lines.join("\n")}"
73
+ @editor.open_scratch_buffer("[LSP Picker]", content)
61
74
  end
62
75
  end
63
76
  end