xlsxrb 0.1.6 → 0.1.8
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 +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +110 -43
- data/Rakefile +16 -5
- data/Steepfile +1 -0
- data/benchmark.rb +32 -4
- data/docs/ARCHITECTURE.md +32 -30
- data/docs/visual/VisualGallery.md +165 -157
- data/docs/wasm/ruby.wasm +0 -0
- data/lib/ruby_lsp/xlsxrb/addon.rb +43 -0
- data/lib/ruby_lsp/xlsxrb/completion_listener.rb +767 -0
- data/lib/xlsxrb/elements/cell.rb +98 -4
- data/lib/xlsxrb/elements/column.rb +22 -0
- data/lib/xlsxrb/elements/coordinate_access.rb +101 -0
- data/lib/xlsxrb/elements/row.rb +81 -1
- data/lib/xlsxrb/elements/types.rb +36 -5
- data/lib/xlsxrb/elements/workbook.rb +92 -6
- data/lib/xlsxrb/elements/worksheet.rb +138 -59
- data/lib/xlsxrb/elements.rb +1 -0
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +21 -15
- data/lib/xlsxrb/stream_row.rb +181 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb.rb +654 -247
- data/sig/generated/xlsxrb/elements/cell.rbs +10 -1
- data/sig/generated/xlsxrb/elements/column.rbs +5 -0
- data/sig/generated/xlsxrb/elements/coordinate_access.rbs +70 -0
- data/sig/generated/xlsxrb/elements/row.rbs +8 -1
- data/sig/generated/xlsxrb/elements/types.rbs +13 -5
- data/sig/generated/xlsxrb/elements/workbook.rbs +8 -1
- data/sig/generated/xlsxrb/elements/worksheet.rbs +121 -12
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +2 -0
- data/sig/generated/xlsxrb/stream_row.rbs +125 -0
- data/sig/generated/xlsxrb.rbs +674 -262
- metadata +7 -1
|
@@ -0,0 +1,767 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLsp
|
|
4
|
+
module Xlsxrb
|
|
5
|
+
# CompletionListener provides intelligent, context-aware method completions
|
|
6
|
+
# for all xlsxrb public block variables (StreamWriter, WorkbookBuilder, WorksheetProxy,
|
|
7
|
+
# StreamSheet, Elements::Workbook, Elements::Worksheet, Elements::Row, Elements::Cell,
|
|
8
|
+
# ChartBuilder, StyleBuilder).
|
|
9
|
+
#
|
|
10
|
+
# Note: This is an interim enhancer for Ruby LSP until native RBS block argument
|
|
11
|
+
# type propagation is fully supported upstream in Ruby LSP / language server tools.
|
|
12
|
+
class CompletionListener
|
|
13
|
+
STREAM_WRITER_ITEMS = [
|
|
14
|
+
{
|
|
15
|
+
label: "sheet",
|
|
16
|
+
detail: "(name = nil, **opts) { |sheet| ... } -> void",
|
|
17
|
+
documentation: "Adds a new worksheet to the streaming XLSX writer and yields a `WorksheetProxy`.\n\n```ruby\nwb.sheet(\"Sales\") do |s|\n s.row([\"Product\", \"Price\"], styles: :bold)\nend\n```"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: "style",
|
|
21
|
+
detail: "(name, **options) -> Symbol",
|
|
22
|
+
documentation: "Registers a reusable named cell style (font, fill, border, alignment, number_format).\n\n```ruby\nwb.style(:bold_blue, font: { bold: true, color: \"0000FF\" })\n```"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
label: "workbook_property",
|
|
26
|
+
detail: "(name, value) -> void",
|
|
27
|
+
documentation: "Sets a workbook-level property (e.g. `:update_links`).\n\n```ruby\nwb.workbook_property(:update_links, \"never\")\n```"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
label: "protect_workbook",
|
|
31
|
+
detail: "(**opts) -> void",
|
|
32
|
+
documentation: "Configures workbook protection options (e.g. `structure: true`, `windows: true`)."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
label: "defined_name",
|
|
36
|
+
detail: "(name, value, sheet: nil, hidden: false) -> void",
|
|
37
|
+
documentation: "Adds a workbook-level defined named range or formula expression."
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
label: "print_area",
|
|
41
|
+
detail: "(range, sheet: nil) -> void",
|
|
42
|
+
documentation: "Sets the print area range for a sheet (e.g. `\"A1:F50\"`)."
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
label: "print_titles",
|
|
46
|
+
detail: "(rows: nil, cols: nil, sheet: nil) -> void",
|
|
47
|
+
documentation: "Sets repeating title rows or columns for printing (e.g. `rows: \"1:2\"`)."
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: "properties",
|
|
51
|
+
detail: "(core: nil, app: nil) -> void",
|
|
52
|
+
documentation: "Sets multiple core and application metadata properties at once."
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: "core_property",
|
|
56
|
+
detail: "(name, value) -> void",
|
|
57
|
+
documentation: "Sets core document metadata (e.g. `:title`, `:creator`, `:subject`, `:keywords`)."
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
label: "app_property",
|
|
61
|
+
detail: "(name, value) -> void",
|
|
62
|
+
documentation: "Sets application document metadata (e.g. `:company`, `:manager`)."
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
label: "custom_property",
|
|
66
|
+
detail: "(name, value, type: :string) -> void",
|
|
67
|
+
documentation: "Adds a custom document property (type: `:string`, `:number`, `:bool`, `:date`)."
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
label: "close",
|
|
71
|
+
detail: "() -> void",
|
|
72
|
+
documentation: "Finalizes the streaming writer and writes the completed XLSX archive."
|
|
73
|
+
}
|
|
74
|
+
].freeze
|
|
75
|
+
|
|
76
|
+
WORKBOOK_BUILDER_ITEMS = [
|
|
77
|
+
{
|
|
78
|
+
label: "sheet",
|
|
79
|
+
detail: "(name = nil, **opts) { |sheet_builder| ... } -> WorksheetBuilder",
|
|
80
|
+
documentation: "Adds a new worksheet to the workbook builder and yields a `WorksheetBuilder`.\n\n```ruby\nwb.sheet(\"Summary\") do |s|\n s.row([\"Item\", \"Total\"])\nend\n```"
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
label: "style",
|
|
84
|
+
detail: "(name, **opts) { |style_builder| ... } -> Symbol",
|
|
85
|
+
documentation: "Defines a named style in the workbook builder."
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
label: "build",
|
|
89
|
+
detail: "() -> Elements::Workbook",
|
|
90
|
+
documentation: "Builds and returns the immutable `Elements::Workbook` DOM hierarchy."
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
label: "workbook_property",
|
|
94
|
+
detail: "(name, value) -> void",
|
|
95
|
+
documentation: "Sets a workbook property."
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
label: "protect_workbook",
|
|
99
|
+
detail: "(**opts) -> void",
|
|
100
|
+
documentation: "Sets workbook protection options."
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
label: "defined_name",
|
|
104
|
+
detail: "(name, value, sheet: nil, hidden: false) -> void",
|
|
105
|
+
documentation: "Adds a defined name or formula to the workbook."
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
label: "print_area",
|
|
109
|
+
detail: "(range, sheet: nil) -> void",
|
|
110
|
+
documentation: "Sets the print area for a sheet."
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
label: "print_titles",
|
|
114
|
+
detail: "(rows: nil, cols: nil, sheet: nil) -> void",
|
|
115
|
+
documentation: "Sets repeating print titles."
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
label: "properties",
|
|
119
|
+
detail: "(core: nil, app: nil) -> void",
|
|
120
|
+
documentation: "Sets multiple metadata properties."
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
label: "core_property",
|
|
124
|
+
detail: "(name, value) -> void",
|
|
125
|
+
documentation: "Sets core document metadata."
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
label: "app_property",
|
|
129
|
+
detail: "(name, value) -> void",
|
|
130
|
+
documentation: "Sets application document metadata."
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
label: "custom_property",
|
|
134
|
+
detail: "(name, value, type: :string) -> void",
|
|
135
|
+
documentation: "Adds a custom document metadata property."
|
|
136
|
+
}
|
|
137
|
+
].freeze
|
|
138
|
+
|
|
139
|
+
WORKSHEET_PROXY_ITEMS = [
|
|
140
|
+
{
|
|
141
|
+
label: "row",
|
|
142
|
+
detail: "(values, styles: nil, height: nil, hidden: false, outline_level: nil) -> void",
|
|
143
|
+
documentation: "Writes a single row of cells with optional style name, height, and outline level.\n\n```ruby\ns.row([\"Product\", \"Price\"], styles: :bold)\ns.row([\"Laptop\", 1200])\n```"
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
label: "column",
|
|
147
|
+
detail: "(col_index, width: nil, hidden: false, outline_level: nil, custom_width: false) -> void",
|
|
148
|
+
documentation: "Configures column formatting (width in characters, visibility, grouping)."
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
label: "merge",
|
|
152
|
+
detail: "(range = nil, row: nil, col_start: nil, col_end: nil) -> void",
|
|
153
|
+
documentation: "Merges a range of cells.\n\n```ruby\ns.merge(\"A1:C1\")\ns.merge(row: 0, col_start: 0, col_end: 2)\n```"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
label: "freeze_pane",
|
|
157
|
+
detail: "(row: 0, col: 0) -> void",
|
|
158
|
+
documentation: "Freezes rows and columns from scrolling (0-based indices).\n\n```ruby\ns.freeze_pane(row: 1, col: 0) # Freeze top header row\n```"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
label: "auto_filter",
|
|
162
|
+
detail: "(range) -> void",
|
|
163
|
+
documentation: "Enables Excel auto-filter dropdown arrows over a cell range (e.g. `\"A1:D100\"`)."
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
label: "hyperlink",
|
|
167
|
+
detail: "(cell, url = nil, display: nil, tooltip: nil, location: nil) -> void",
|
|
168
|
+
documentation: "Adds a clickable hyperlink to a cell reference.\n\n```ruby\ns.hyperlink(\"A1\", \"https://example.com\", display: \"Example\")\n```"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
label: "chart",
|
|
172
|
+
detail: "(type = nil, **opts) { |chart| ... } -> void",
|
|
173
|
+
documentation: "Adds a chart (bar, column, line, pie, scatter, area, doughnut, radar) to the worksheet."
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
label: "table",
|
|
177
|
+
detail: "(range, name: \"Table1\", **opts) -> void",
|
|
178
|
+
documentation: "Adds a formatted Excel Table to the range."
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
label: "conditional_format",
|
|
182
|
+
detail: "(range, type: \"cellIs\", **opts) -> void",
|
|
183
|
+
documentation: "Adds conditional formatting rules (cellIs, colorScale, dataBar, expression)."
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
label: "validate_data",
|
|
187
|
+
detail: "(range, type: \"list\", **opts) -> void",
|
|
188
|
+
documentation: "Adds data validation rules (dropdown list, whole number, decimal, date range, custom formula)."
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
label: "image",
|
|
192
|
+
detail: "(file_data, ext: \"png\", from_col: 0, from_row: 0, to_col: 5, to_row: 10, **opts) -> void",
|
|
193
|
+
documentation: "Inserts an image into the worksheet."
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
label: "comment",
|
|
197
|
+
detail: "(cell, text, author: nil) -> void",
|
|
198
|
+
documentation: "Adds an author comment / note to a cell."
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
label: "sparkline_group",
|
|
202
|
+
detail: "(range:, type: \"line\", sparklines:, **opts) -> void",
|
|
203
|
+
documentation: "Adds in-cell sparklines (line, column, win_loss)."
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
label: "pivot_table",
|
|
207
|
+
detail: "(range, name:, row_fields:, data_fields:, **opts) -> void",
|
|
208
|
+
documentation: "Creates a native Excel Pivot Table from worksheet data."
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
label: "shape",
|
|
212
|
+
detail: "(preset: \"rect\", text: nil, from_col: 0, from_row: 0, to_col: 5, to_row: 5, **opts) -> void",
|
|
213
|
+
documentation: "Adds a drawing shape to the sheet."
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
label: "page_setup",
|
|
217
|
+
detail: "(orientation: \"portrait\", paper_size: 9, **opts) -> void",
|
|
218
|
+
documentation: "Configures page orientation (portrait/landscape), paper size (e.g. 9 for A4), and scaling."
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
label: "page_margins",
|
|
222
|
+
detail: "(left: nil, right: nil, top: nil, bottom: nil, header: nil, footer: nil) -> void",
|
|
223
|
+
documentation: "Configures print page margins in inches."
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
label: "header_footer",
|
|
227
|
+
detail: "(**opts) -> void",
|
|
228
|
+
documentation: "Configures print header and footer text."
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
label: "print_options",
|
|
232
|
+
detail: "(name, value) -> void",
|
|
233
|
+
documentation: "Configures print options (e.g. `s.print_options(:grid_lines, true)`)."
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
label: "protect_sheet",
|
|
237
|
+
detail: "(**opts) -> void",
|
|
238
|
+
documentation: "Protects worksheet with optional password hashing and capability flags."
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
label: "sheet_view",
|
|
242
|
+
detail: "(name, value) -> void",
|
|
243
|
+
documentation: "Sets view settings (e.g. `s.sheet_view(:show_grid_lines, false)`)."
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
label: "sheet_properties",
|
|
247
|
+
detail: "(name, value) -> void",
|
|
248
|
+
documentation: "Sets sheet properties (e.g. `s.sheet_properties(:tab_color, \"FF0000\")`)."
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
label: "select_cell",
|
|
252
|
+
detail: "(active_cell, sqref: nil, pane: nil) -> void",
|
|
253
|
+
documentation: "Sets the active / selected cell when opening the worksheet in Excel."
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
label: "split_pane",
|
|
257
|
+
detail: "(x_split: 0, y_split: 0, top_left_cell: nil) -> void",
|
|
258
|
+
documentation: "Splits worksheet view into independent scrollable panes."
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
label: "filter_column",
|
|
262
|
+
detail: "(col_id, filter_values) -> void",
|
|
263
|
+
documentation: "Sets filter criteria for a column within the auto-filter range."
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
label: "sort_state",
|
|
267
|
+
detail: "(ref, sort_conditions, **opts) -> void",
|
|
268
|
+
documentation: "Configures sort state conditions on a cell range."
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
label: "page_break_row",
|
|
272
|
+
detail: "(row_num) -> void",
|
|
273
|
+
documentation: "Adds a horizontal page break before the given row index."
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
label: "page_break_col",
|
|
277
|
+
detail: "(col_index) -> void",
|
|
278
|
+
documentation: "Adds a vertical page break before the given column index."
|
|
279
|
+
}
|
|
280
|
+
].freeze
|
|
281
|
+
|
|
282
|
+
STREAM_SHEET_ITEMS = [
|
|
283
|
+
{
|
|
284
|
+
label: "each_row",
|
|
285
|
+
detail: "() { |row| ... } -> void",
|
|
286
|
+
documentation: "Yields each row in the streaming sheet as an `Elements::Row`.\n\n```ruby\nsheet.each_row do |row|\n puts row.to_a.inspect\nend\n```"
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
label: "each",
|
|
290
|
+
detail: "() { |row| ... } -> void",
|
|
291
|
+
documentation: "Yields each row in the streaming sheet."
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
label: "name",
|
|
295
|
+
detail: "() -> String",
|
|
296
|
+
documentation: "Returns the worksheet name."
|
|
297
|
+
}
|
|
298
|
+
].freeze
|
|
299
|
+
|
|
300
|
+
WORKBOOK_ELEMENT_ITEMS = [
|
|
301
|
+
{
|
|
302
|
+
label: "sheet",
|
|
303
|
+
detail: "(index_or_name) -> Elements::Worksheet?",
|
|
304
|
+
documentation: "Returns the worksheet by 0-based index or name.\n\n```ruby\nsheet = workbook.sheet(0)\n```"
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
label: "[]",
|
|
308
|
+
detail: "(index_or_name) -> Elements::Worksheet?",
|
|
309
|
+
documentation: "Returns the worksheet by 0-based index or name.\n\n```ruby\nsheet = workbook[\"Sheet1\"]\n```"
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
label: "update_sheet",
|
|
313
|
+
detail: "(name_or_index, sheet) -> Elements::Workbook",
|
|
314
|
+
documentation: "Replaces or updates a sheet and returns a new `Elements::Workbook`."
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
label: "sheet_names",
|
|
318
|
+
detail: "() -> Array<String>",
|
|
319
|
+
documentation: "Returns the list of all sheet names in the workbook."
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
label: "each",
|
|
323
|
+
detail: "() { |sheet| ... } -> void",
|
|
324
|
+
documentation: "Yields each `Elements::Worksheet` in the workbook.\n\n```ruby\nworkbook.each do |sheet|\n puts sheet.name\nend\n```"
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
label: "save",
|
|
328
|
+
detail: "(target_path_or_io) -> void",
|
|
329
|
+
documentation: "Writes the workbook DOM to a target XLSX file or IO stream."
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
label: "valid?",
|
|
333
|
+
detail: "() -> Boolean",
|
|
334
|
+
documentation: "Returns true if all workbook elements and sheets are valid."
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
label: "validate",
|
|
338
|
+
detail: "() -> Array<String>",
|
|
339
|
+
documentation: "Validates workbook structure and returns any validation errors."
|
|
340
|
+
}
|
|
341
|
+
].freeze
|
|
342
|
+
|
|
343
|
+
WORKSHEET_ELEMENT_ITEMS = [
|
|
344
|
+
{
|
|
345
|
+
label: "[]",
|
|
346
|
+
detail: "(cell_ref) -> Elements::Cell?",
|
|
347
|
+
documentation: "Finds and returns a cell by A1 reference.\n\n```ruby\ncell = sheet[\"B2\"]\n```"
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
label: "cell_value",
|
|
351
|
+
detail: "(cell_ref) -> Object?",
|
|
352
|
+
documentation: "Returns the raw value of the cell at the given A1 reference."
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
label: "each_row",
|
|
356
|
+
detail: "() { |row| ... } -> void",
|
|
357
|
+
documentation: "Yields each row in the worksheet as an `Elements::Row`.\n\n```ruby\nsheet.each_row do |row|\n puts row.to_a.inspect\nend\n```"
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
label: "each",
|
|
361
|
+
detail: "() { |row| ... } -> void",
|
|
362
|
+
documentation: "Yields each row in the worksheet as an `Elements::Row`."
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
label: "each_cell",
|
|
366
|
+
detail: "() { |cell| ... } -> void",
|
|
367
|
+
documentation: "Yields every `Elements::Cell` across all rows."
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
label: "update_cell",
|
|
371
|
+
detail: "(ref, new_value) -> Elements::Worksheet",
|
|
372
|
+
documentation: "Returns a new worksheet with the updated cell value."
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
label: "row_at",
|
|
376
|
+
detail: "(row_index) -> Elements::Row?",
|
|
377
|
+
documentation: "Returns the row at the 0-based row index."
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
label: "first_row",
|
|
381
|
+
detail: "() -> Elements::Row?",
|
|
382
|
+
documentation: "Returns the first row in the sheet."
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
label: "last_row",
|
|
386
|
+
detail: "() -> Elements::Row?",
|
|
387
|
+
documentation: "Returns the last row in the sheet."
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
label: "cells",
|
|
391
|
+
detail: "() -> Array<Elements::Cell>",
|
|
392
|
+
documentation: "Returns a flat array of all cells in the sheet."
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
label: "cells_hash",
|
|
396
|
+
detail: "() -> Hash<String, Elements::Cell>",
|
|
397
|
+
documentation: "Returns a hash mapping A1 references to `Elements::Cell` objects."
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
label: "name",
|
|
401
|
+
detail: "() -> String",
|
|
402
|
+
documentation: "Returns the worksheet name."
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
label: "valid?",
|
|
406
|
+
detail: "() -> Boolean",
|
|
407
|
+
documentation: "Returns true if all cells and rows in the worksheet are valid."
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
label: "validate",
|
|
411
|
+
detail: "() -> Array<String>",
|
|
412
|
+
documentation: "Returns any validation errors found in the worksheet."
|
|
413
|
+
}
|
|
414
|
+
].freeze
|
|
415
|
+
|
|
416
|
+
ROW_ELEMENT_ITEMS = [
|
|
417
|
+
{
|
|
418
|
+
label: "[]",
|
|
419
|
+
detail: "(col_index_or_symbol) -> Elements::Cell? | Object?",
|
|
420
|
+
documentation: "Returns the cell at 0-based column index, or access property symbol (`:cells`, `:index`, `:height`).\n\n```ruby\ncell = row[0]\n```"
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
label: "to_a",
|
|
424
|
+
detail: "() -> Array<Object?>",
|
|
425
|
+
documentation: "Returns an array containing the values of all cells in this row.\n\n```ruby\nvalues = row.to_a\n```"
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
label: "values",
|
|
429
|
+
detail: "() -> Array<Object?>",
|
|
430
|
+
documentation: "Returns an array of cell values in this row."
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
label: "cell_at",
|
|
434
|
+
detail: "(col_index) -> Elements::Cell?",
|
|
435
|
+
documentation: "Returns the cell at the 0-based column index."
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
label: "each",
|
|
439
|
+
detail: "() { |cell| ... } -> void",
|
|
440
|
+
documentation: "Yields each `Elements::Cell` in this row."
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
label: "each_cell",
|
|
444
|
+
detail: "() { |cell| ... } -> void",
|
|
445
|
+
documentation: "Yields each `Elements::Cell` in this row."
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
label: "cells",
|
|
449
|
+
detail: "() -> Array<Elements::Cell>",
|
|
450
|
+
documentation: "Returns the list of cells in this row."
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
label: "index",
|
|
454
|
+
detail: "() -> Integer",
|
|
455
|
+
documentation: "Returns the 0-based row index."
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
label: "height",
|
|
459
|
+
detail: "() -> Float?",
|
|
460
|
+
documentation: "Returns custom row height in points, or nil."
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
label: "valid?",
|
|
464
|
+
detail: "() -> Boolean",
|
|
465
|
+
documentation: "Returns true if all cells in this row are valid."
|
|
466
|
+
},
|
|
467
|
+
{
|
|
468
|
+
label: "validate",
|
|
469
|
+
detail: "() -> Array<String>",
|
|
470
|
+
documentation: "Validates all cells in this row and returns error messages."
|
|
471
|
+
}
|
|
472
|
+
].freeze
|
|
473
|
+
|
|
474
|
+
CELL_ELEMENT_ITEMS = [
|
|
475
|
+
{
|
|
476
|
+
label: "value",
|
|
477
|
+
detail: "() -> Object?",
|
|
478
|
+
documentation: "Returns the cell's typed value (String, Integer, Float, Date, Time, nil)."
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
label: "ref",
|
|
482
|
+
detail: "() -> String",
|
|
483
|
+
documentation: "Returns the cell's A1 reference (e.g. `\"B2\"`)."
|
|
484
|
+
},
|
|
485
|
+
{
|
|
486
|
+
label: "to_s",
|
|
487
|
+
detail: "() -> String",
|
|
488
|
+
documentation: "Returns string representation of cell value."
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
label: "to_i",
|
|
492
|
+
detail: "() -> Integer",
|
|
493
|
+
documentation: "Converts cell value to Integer."
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
label: "to_f",
|
|
497
|
+
detail: "() -> Float",
|
|
498
|
+
documentation: "Converts cell value to Float."
|
|
499
|
+
},
|
|
500
|
+
{
|
|
501
|
+
label: "to_date",
|
|
502
|
+
detail: "() -> Date?",
|
|
503
|
+
documentation: "Converts cell value to Date."
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
label: "to_time",
|
|
507
|
+
detail: "() -> Time?",
|
|
508
|
+
documentation: "Converts cell value to Time."
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
label: "column_letter",
|
|
512
|
+
detail: "() -> String",
|
|
513
|
+
documentation: "Returns the column letters (e.g. `\"A\"`, `\"AA\"`)."
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
label: "row_index",
|
|
517
|
+
detail: "() -> Integer",
|
|
518
|
+
documentation: "Returns the 0-based row index."
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
label: "column_index",
|
|
522
|
+
detail: "() -> Integer",
|
|
523
|
+
documentation: "Returns the 0-based column index."
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
label: "style_index",
|
|
527
|
+
detail: "() -> Integer?",
|
|
528
|
+
documentation: "Returns the 0-based index into stylesheet formatting."
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
label: "content",
|
|
532
|
+
detail: "() -> String",
|
|
533
|
+
documentation: "Returns string content of cell value."
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
label: "[]",
|
|
537
|
+
detail: "(symbol) -> Object?",
|
|
538
|
+
documentation: "Hash-style access to cell attributes (`:value`, `:ref`, `:style_index`)."
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
label: "valid?",
|
|
542
|
+
detail: "() -> Boolean",
|
|
543
|
+
documentation: "Returns true if row_index, column_index, and value are valid."
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
label: "validate",
|
|
547
|
+
detail: "() -> Array<String>",
|
|
548
|
+
documentation: "Returns validation errors if indices are negative or invalid."
|
|
549
|
+
}
|
|
550
|
+
].freeze
|
|
551
|
+
|
|
552
|
+
CHART_BUILDER_ITEMS = [
|
|
553
|
+
{
|
|
554
|
+
label: "title",
|
|
555
|
+
detail: "(text) -> void",
|
|
556
|
+
documentation: "Sets the chart title text."
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
label: "series",
|
|
560
|
+
detail: "(range, name: nil) -> void",
|
|
561
|
+
documentation: "Adds data series value range."
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
label: "categories",
|
|
565
|
+
detail: "(range) -> void",
|
|
566
|
+
documentation: "Sets category label range (e.g. `'Sheet1!$A$2:$A$10'`)."
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
label: "legend",
|
|
570
|
+
detail: "(position: 'r') -> void",
|
|
571
|
+
documentation: "Configures legend position (`'r'`, `'l'`, `'t'`, `'b'`, `'none'`)."
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
label: "plot_by",
|
|
575
|
+
detail: "(grouping) -> void",
|
|
576
|
+
documentation: "Sets series grouping (`'standard'`, `'stacked'`, `'percentStacked'`)."
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
label: "dimension",
|
|
580
|
+
detail: "(from_col: 0, from_row: 0, to_col: 8, to_row: 15) -> void",
|
|
581
|
+
documentation: "Sets chart position and size on the worksheet."
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
label: "gridlines",
|
|
585
|
+
detail: "(horizontal: true, vertical: false) -> void",
|
|
586
|
+
documentation: "Configures chart major gridlines."
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
label: "style",
|
|
590
|
+
detail: "(id) -> void",
|
|
591
|
+
documentation: "Sets built-in chart style number (1-48)."
|
|
592
|
+
}
|
|
593
|
+
].freeze
|
|
594
|
+
|
|
595
|
+
STYLE_BUILDER_ITEMS = [
|
|
596
|
+
{
|
|
597
|
+
label: "font",
|
|
598
|
+
detail: "(name: 'Calibri', size: 11, bold: false, italic: false, underline: false, color: nil) -> void",
|
|
599
|
+
documentation: "Sets font typography, size, weight, and color."
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
label: "fill",
|
|
603
|
+
detail: "(pattern: 'solid', fg_color: nil, bg_color: nil) -> void",
|
|
604
|
+
documentation: "Sets background fill pattern and foreground color."
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
label: "border",
|
|
608
|
+
detail: "(left: nil, right: nil, top: nil, bottom: nil) -> void",
|
|
609
|
+
documentation: "Sets cell border lines and colors."
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
label: "alignment",
|
|
613
|
+
detail: "(horizontal: nil, vertical: nil, wrap_text: false, rotation: 0) -> void",
|
|
614
|
+
documentation: "Sets cell text alignment and text wrap."
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
label: "number_format",
|
|
618
|
+
detail: "(format_code_or_id) -> void",
|
|
619
|
+
documentation: "Sets custom number or date format code (e.g. `'#,##0.00'`, `'yyyy-mm-dd'`)."
|
|
620
|
+
}
|
|
621
|
+
].freeze
|
|
622
|
+
|
|
623
|
+
CLASS_NAMES = {
|
|
624
|
+
stream_writer: "Xlsxrb::StreamWriter",
|
|
625
|
+
workbook_builder: "Xlsxrb::WorkbookBuilder",
|
|
626
|
+
worksheet_proxy: "Xlsxrb::StreamWriter::WorksheetProxy",
|
|
627
|
+
stream_sheet: "Xlsxrb::StreamSheet",
|
|
628
|
+
workbook: "Xlsxrb::Elements::Workbook",
|
|
629
|
+
worksheet: "Xlsxrb::Elements::Worksheet",
|
|
630
|
+
row: "Xlsxrb::Elements::Row",
|
|
631
|
+
cell: "Xlsxrb::Elements::Cell",
|
|
632
|
+
chart_builder: "Xlsxrb::ChartBuilder",
|
|
633
|
+
style_builder: "Xlsxrb::StyleBuilder"
|
|
634
|
+
}.freeze
|
|
635
|
+
|
|
636
|
+
ITEMS_BY_TYPE = {
|
|
637
|
+
stream_writer: STREAM_WRITER_ITEMS,
|
|
638
|
+
workbook_builder: WORKBOOK_BUILDER_ITEMS,
|
|
639
|
+
worksheet_proxy: WORKSHEET_PROXY_ITEMS,
|
|
640
|
+
stream_sheet: STREAM_SHEET_ITEMS,
|
|
641
|
+
workbook: WORKBOOK_ELEMENT_ITEMS,
|
|
642
|
+
worksheet: WORKSHEET_ELEMENT_ITEMS,
|
|
643
|
+
row: ROW_ELEMENT_ITEMS,
|
|
644
|
+
cell: CELL_ELEMENT_ITEMS,
|
|
645
|
+
chart_builder: CHART_BUILDER_ITEMS,
|
|
646
|
+
style_builder: STYLE_BUILDER_ITEMS
|
|
647
|
+
}.freeze
|
|
648
|
+
|
|
649
|
+
def initialize(response_builder, node_context, dispatcher, global_state)
|
|
650
|
+
@response_builder = response_builder
|
|
651
|
+
@node_context = node_context
|
|
652
|
+
@global_state = global_state
|
|
653
|
+
|
|
654
|
+
dispatcher.register(self, :on_call_node_enter)
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
def on_call_node_enter(node)
|
|
658
|
+
receiver = node.receiver
|
|
659
|
+
receiver_name = receiver.name if receiver.is_a?(Prism::LocalVariableReadNode) || (receiver.is_a?(Prism::CallNode) && receiver.receiver.nil?)
|
|
660
|
+
return unless receiver_name
|
|
661
|
+
|
|
662
|
+
target_type = infer_target_type(receiver_name)
|
|
663
|
+
return unless target_type
|
|
664
|
+
|
|
665
|
+
items = ITEMS_BY_TYPE[target_type]
|
|
666
|
+
return unless items
|
|
667
|
+
|
|
668
|
+
detail_prefix = "(#{CLASS_NAMES[target_type]}) "
|
|
669
|
+
items.each_with_index do |item, index|
|
|
670
|
+
sort_key = "#{index.to_s.rjust(3, "0")}_#{item[:label]}"
|
|
671
|
+
@response_builder << ::RubyLsp::Interface::CompletionItem.new(
|
|
672
|
+
label: item[:label],
|
|
673
|
+
kind: ::RubyLsp::Constant::CompletionItemKind::METHOD,
|
|
674
|
+
detail: "#{detail_prefix}#{item[:detail]}",
|
|
675
|
+
sort_text: sort_key,
|
|
676
|
+
documentation: {
|
|
677
|
+
kind: ::RubyLsp::Constant::MarkupKind::MARKDOWN,
|
|
678
|
+
value: item[:documentation]
|
|
679
|
+
}
|
|
680
|
+
)
|
|
681
|
+
end
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
private
|
|
685
|
+
|
|
686
|
+
def infer_target_type(receiver_name)
|
|
687
|
+
parent = @node_context&.parent
|
|
688
|
+
|
|
689
|
+
# 1. AST Context Analysis: Inspect enclosing block caller
|
|
690
|
+
if parent.is_a?(Prism::CallNode)
|
|
691
|
+
method_name = parent.name
|
|
692
|
+
caller_receiver = parent.receiver
|
|
693
|
+
|
|
694
|
+
if caller_receiver_is_xlsxrb?(caller_receiver)
|
|
695
|
+
case method_name
|
|
696
|
+
when :write then return :stream_writer
|
|
697
|
+
when :read then return :stream_sheet
|
|
698
|
+
when :build then return :workbook_builder
|
|
699
|
+
when :modify then return :workbook
|
|
700
|
+
end
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
case method_name
|
|
704
|
+
when :sheet then return :worksheet_proxy
|
|
705
|
+
when :chart then return :chart_builder
|
|
706
|
+
when :style then return :style_builder
|
|
707
|
+
when :each_row then return :row
|
|
708
|
+
when :each_cell then return :cell
|
|
709
|
+
when :each
|
|
710
|
+
return infer_each_block_target(caller_receiver)
|
|
711
|
+
end
|
|
712
|
+
end
|
|
713
|
+
|
|
714
|
+
# 2. Variable Name Heuristics (fallback if parent node wasn't direct)
|
|
715
|
+
infer_from_variable_name(receiver_name)
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
def infer_each_block_target(caller_receiver)
|
|
719
|
+
if receiver_matches?(caller_receiver, %i[workbook wb])
|
|
720
|
+
:worksheet
|
|
721
|
+
elsif receiver_matches?(caller_receiver, %i[row r stream_row])
|
|
722
|
+
:cell
|
|
723
|
+
else
|
|
724
|
+
:row
|
|
725
|
+
end
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
def infer_from_variable_name(name)
|
|
729
|
+
case name
|
|
730
|
+
when :wb, :workbook
|
|
731
|
+
:workbook_builder
|
|
732
|
+
when :s, :sheet, :ws, :worksheet
|
|
733
|
+
:worksheet_proxy
|
|
734
|
+
when :stream_sheet, :ss
|
|
735
|
+
:stream_sheet
|
|
736
|
+
when :stream_writer, :sw
|
|
737
|
+
:stream_writer
|
|
738
|
+
when :r, :row
|
|
739
|
+
:row
|
|
740
|
+
when :c, :cell
|
|
741
|
+
:cell
|
|
742
|
+
when :chart, :chart_builder, :cb
|
|
743
|
+
:chart_builder
|
|
744
|
+
when :style, :style_builder, :sb
|
|
745
|
+
:style_builder
|
|
746
|
+
end
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
def caller_receiver_is_xlsxrb?(receiver)
|
|
750
|
+
return false unless receiver
|
|
751
|
+
|
|
752
|
+
if receiver.is_a?(Prism::ConstantReadNode) || receiver.is_a?(Prism::ConstantPathNode)
|
|
753
|
+
receiver.slice == "Xlsxrb"
|
|
754
|
+
else
|
|
755
|
+
false
|
|
756
|
+
end
|
|
757
|
+
end
|
|
758
|
+
|
|
759
|
+
def receiver_matches?(receiver, names)
|
|
760
|
+
return false unless receiver
|
|
761
|
+
|
|
762
|
+
rec_name = receiver.name if receiver.is_a?(Prism::LocalVariableReadNode) || (receiver.is_a?(Prism::CallNode) && receiver.receiver.nil?)
|
|
763
|
+
names.include?(rec_name)
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
end
|
|
767
|
+
end
|