t-ruby 0.0.35 → 0.0.36

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.
@@ -10,13 +10,13 @@ module TRuby
10
10
 
11
11
  # LSP Error codes
12
12
  module ErrorCodes
13
- PARSE_ERROR = -32700
14
- INVALID_REQUEST = -32600
15
- METHOD_NOT_FOUND = -32601
16
- INVALID_PARAMS = -32602
17
- INTERNAL_ERROR = -32603
18
- SERVER_NOT_INITIALIZED = -32002
19
- UNKNOWN_ERROR_CODE = -32001
13
+ PARSE_ERROR = -32_700
14
+ INVALID_REQUEST = -32_600
15
+ METHOD_NOT_FOUND = -32_601
16
+ INVALID_PARAMS = -32_602
17
+ INTERNAL_ERROR = -32_603
18
+ SERVER_NOT_INITIALIZED = -32_002
19
+ UNKNOWN_ERROR_CODE = -32_001
20
20
  end
21
21
 
22
22
  # LSP Completion item kinds
@@ -152,7 +152,7 @@ module TRuby
152
152
  end
153
153
 
154
154
  content_length = headers["Content-Length"]&.to_i
155
- return nil unless content_length && content_length > 0
155
+ return nil unless content_length&.positive?
156
156
 
157
157
  # Read content
158
158
  content = @input.read(content_length)
@@ -178,7 +178,7 @@ module TRuby
178
178
  notification = {
179
179
  "jsonrpc" => "2.0",
180
180
  "method" => method,
181
- "params" => params
181
+ "params" => params,
182
182
  }
183
183
  send_response(notification)
184
184
  end
@@ -210,7 +210,7 @@ module TRuby
210
210
 
211
211
  private
212
212
 
213
- def dispatch_method(method, params, id)
213
+ def dispatch_method(method, params, _id)
214
214
  case method
215
215
  when "initialize"
216
216
  handle_initialize(params)
@@ -253,31 +253,31 @@ module TRuby
253
253
  "textDocumentSync" => {
254
254
  "openClose" => true,
255
255
  "change" => 1, # Full sync
256
- "save" => { "includeText" => true }
256
+ "save" => { "includeText" => true },
257
257
  },
258
258
  "completionProvider" => {
259
259
  "triggerCharacters" => [":", "<", "|", "&"],
260
- "resolveProvider" => false
260
+ "resolveProvider" => false,
261
261
  },
262
262
  "hoverProvider" => true,
263
263
  "definitionProvider" => true,
264
264
  "diagnosticProvider" => {
265
265
  "interFileDependencies" => false,
266
- "workspaceDiagnostics" => false
266
+ "workspaceDiagnostics" => false,
267
267
  },
268
268
  "semanticTokensProvider" => {
269
269
  "legend" => {
270
270
  "tokenTypes" => SEMANTIC_TOKEN_TYPES,
271
- "tokenModifiers" => SEMANTIC_TOKEN_MODIFIERS
271
+ "tokenModifiers" => SEMANTIC_TOKEN_MODIFIERS,
272
272
  },
273
273
  "full" => true,
274
- "range" => false
275
- }
274
+ "range" => false,
275
+ },
276
276
  },
277
277
  "serverInfo" => {
278
278
  "name" => "t-ruby-lsp",
279
- "version" => VERSION
280
- }
279
+ "version" => VERSION,
280
+ },
281
281
  }
282
282
  end
283
283
 
@@ -304,7 +304,7 @@ module TRuby
304
304
 
305
305
  @documents[uri] = {
306
306
  text: text,
307
- version: text_document["version"]
307
+ version: text_document["version"],
308
308
  }
309
309
 
310
310
  # Parse and send diagnostics
@@ -321,7 +321,7 @@ module TRuby
321
321
  if changes && !changes.empty?
322
322
  @documents[uri] = {
323
323
  text: changes.last["text"],
324
- version: text_document["version"]
324
+ version: text_document["version"],
325
325
  }
326
326
 
327
327
  # Re-parse and send diagnostics
@@ -336,9 +336,9 @@ module TRuby
336
336
 
337
337
  # Clear diagnostics
338
338
  send_notification("textDocument/publishDiagnostics", {
339
- "uri" => uri,
340
- "diagnostics" => []
341
- })
339
+ "uri" => uri,
340
+ "diagnostics" => [],
341
+ })
342
342
  nil
343
343
  end
344
344
 
@@ -363,9 +363,9 @@ module TRuby
363
363
  diagnostics = analyze_document(text)
364
364
 
365
365
  send_notification("textDocument/publishDiagnostics", {
366
- "uri" => uri,
367
- "diagnostics" => diagnostics
368
- })
366
+ "uri" => uri,
367
+ "diagnostics" => diagnostics,
368
+ })
369
369
  end
370
370
 
371
371
  def analyze_document(text)
@@ -377,12 +377,12 @@ module TRuby
377
377
 
378
378
  errors.each do |error|
379
379
  # Parse line number from error message
380
- if error =~ /^Line (\d+):\s*(.+)$/
381
- line_num = Regexp.last_match(1).to_i - 1 # LSP uses 0-based line numbers
382
- message = Regexp.last_match(2)
380
+ next unless error =~ /^Line (\d+):\s*(.+)$/
383
381
 
384
- diagnostics << create_diagnostic(line_num, message, DiagnosticSeverity::ERROR)
385
- end
382
+ line_num = Regexp.last_match(1).to_i - 1 # LSP uses 0-based line numbers
383
+ message = Regexp.last_match(2)
384
+
385
+ diagnostics << create_diagnostic(line_num, message, DiagnosticSeverity::ERROR)
386
386
  end
387
387
 
388
388
  # Additional validation using Parser
@@ -428,25 +428,23 @@ module TRuby
428
428
  next unless line_num
429
429
 
430
430
  # Validate return type
431
- if func[:return_type]
432
- unless valid_type?(func[:return_type])
433
- diagnostics << create_diagnostic(
434
- line_num,
435
- "Unknown return type '#{func[:return_type]}'",
436
- DiagnosticSeverity::WARNING
437
- )
438
- end
431
+ if func[:return_type] && !valid_type?(func[:return_type])
432
+ diagnostics << create_diagnostic(
433
+ line_num,
434
+ "Unknown return type '#{func[:return_type]}'",
435
+ DiagnosticSeverity::WARNING
436
+ )
439
437
  end
440
438
 
441
439
  # Validate parameter types
442
440
  func[:params]&.each do |param|
443
- if param[:type] && !valid_type?(param[:type])
444
- diagnostics << create_diagnostic(
445
- line_num,
446
- "Unknown parameter type '#{param[:type]}' for '#{param[:name]}'",
447
- DiagnosticSeverity::WARNING
448
- )
449
- end
441
+ next unless param[:type] && !valid_type?(param[:type])
442
+
443
+ diagnostics << create_diagnostic(
444
+ line_num,
445
+ "Unknown parameter type '#{param[:type]}' for '#{param[:name]}'",
446
+ DiagnosticSeverity::WARNING
447
+ )
450
448
  end
451
449
  end
452
450
  end
@@ -484,11 +482,11 @@ module TRuby
484
482
  {
485
483
  "range" => {
486
484
  "start" => { "line" => line, "character" => 0 },
487
- "end" => { "line" => line, "character" => 1000 }
485
+ "end" => { "line" => line, "character" => 1000 },
488
486
  },
489
487
  "severity" => severity,
490
488
  "source" => "t-ruby",
491
- "message" => message
489
+ "message" => message,
492
490
  }
493
491
  end
494
492
 
@@ -512,28 +510,29 @@ module TRuby
512
510
  completions = []
513
511
 
514
512
  # Context-aware completion
515
- if prefix =~ /:\s*$/
513
+ case prefix
514
+ when /:\s*$/
516
515
  # After colon - suggest types
517
516
  completions.concat(type_completions)
518
- elsif prefix =~ /\|\s*$/
517
+ when /\|\s*$/
519
518
  # After pipe - suggest types for union
520
519
  completions.concat(type_completions)
521
- elsif prefix =~ /&\s*$/
520
+ when /&\s*$/
522
521
  # After ampersand - suggest types for intersection
523
522
  completions.concat(type_completions)
524
- elsif prefix =~ /<\s*$/
523
+ when /<\s*$/
525
524
  # Inside generic - suggest types
526
525
  completions.concat(type_completions)
527
- elsif prefix =~ /^\s*$/
526
+ when /^\s*$/
528
527
  # Start of line - suggest keywords
529
528
  completions.concat(keyword_completions)
530
- elsif prefix =~ /^\s*def\s+\w*$/
529
+ when /^\s*def\s+\w*$/
531
530
  # Function definition - no completion needed
532
531
  completions = []
533
- elsif prefix =~ /^\s*type\s+\w*$/
532
+ when /^\s*type\s+\w*$/
534
533
  # Type alias definition - no completion needed
535
534
  completions = []
536
- elsif prefix =~ /^\s*interface\s+\w*$/
535
+ when /^\s*interface\s+\w*$/
537
536
  # Interface definition - no completion needed
538
537
  completions = []
539
538
  else
@@ -554,7 +553,7 @@ module TRuby
554
553
  "label" => type,
555
554
  "kind" => CompletionItemKind::CLASS,
556
555
  "detail" => "Built-in type",
557
- "documentation" => "T-Ruby built-in type: #{type}"
556
+ "documentation" => "T-Ruby built-in type: #{type}",
558
557
  }
559
558
  end
560
559
  end
@@ -565,7 +564,7 @@ module TRuby
565
564
  "label" => keyword,
566
565
  "kind" => CompletionItemKind::KEYWORD,
567
566
  "detail" => "Keyword",
568
- "documentation" => keyword_documentation(keyword)
567
+ "documentation" => keyword_documentation(keyword),
569
568
  }
570
569
  end
571
570
  end
@@ -586,17 +585,16 @@ module TRuby
586
585
  end
587
586
 
588
587
  def document_type_completions(text)
589
- completions = []
590
588
  parser = Parser.new(text)
591
589
  result = parser.parse
592
590
 
593
591
  # Add type aliases from the document
594
- (result[:type_aliases] || []).each do |alias_info|
595
- completions << {
592
+ completions = (result[:type_aliases] || []).map do |alias_info|
593
+ {
596
594
  "label" => alias_info[:name],
597
595
  "kind" => CompletionItemKind::CLASS,
598
596
  "detail" => "Type alias",
599
- "documentation" => "type #{alias_info[:name]} = #{alias_info[:definition]}"
597
+ "documentation" => "type #{alias_info[:name]} = #{alias_info[:definition]}",
600
598
  }
601
599
  end
602
600
 
@@ -606,7 +604,7 @@ module TRuby
606
604
  "label" => interface_info[:name],
607
605
  "kind" => CompletionItemKind::INTERFACE,
608
606
  "detail" => "Interface",
609
- "documentation" => "interface #{interface_info[:name]}"
607
+ "documentation" => "interface #{interface_info[:name]}",
610
608
  }
611
609
  end
612
610
 
@@ -637,9 +635,9 @@ module TRuby
637
635
  {
638
636
  "contents" => {
639
637
  "kind" => "markdown",
640
- "value" => hover_info
638
+ "value" => hover_info,
641
639
  },
642
- "range" => word_range(position["line"], line, char_pos, word)
640
+ "range" => word_range(position["line"], line, char_pos, word),
643
641
  }
644
642
  end
645
643
 
@@ -651,14 +649,10 @@ module TRuby
651
649
  end_pos = char_pos
652
650
 
653
651
  # Move start back to word start
654
- while start_pos > 0 && line[start_pos - 1] =~ /[\w<>]/
655
- start_pos -= 1
656
- end
652
+ start_pos -= 1 while start_pos.positive? && line[start_pos - 1] =~ /[\w<>]/
657
653
 
658
654
  # Move end forward to word end
659
- while end_pos < line.length && line[end_pos] =~ /[\w<>]/
660
- end_pos += 1
661
- end
655
+ end_pos += 1 while end_pos < line.length && line[end_pos] =~ /[\w<>]/
662
656
 
663
657
  return nil if start_pos == end_pos
664
658
 
@@ -671,7 +665,7 @@ module TRuby
671
665
 
672
666
  {
673
667
  "start" => { "line" => line_num, "character" => start_pos },
674
- "end" => { "line" => line_num, "character" => end_pos }
668
+ "end" => { "line" => line_num, "character" => end_pos },
675
669
  }
676
670
  end
677
671
 
@@ -701,11 +695,11 @@ module TRuby
701
695
 
702
696
  # Check if it's a function
703
697
  (result[:functions] || []).each do |func|
704
- if func[:name] == word
705
- params = func[:params].map { |p| "#{p[:name]}: #{p[:type] || 'untyped'}" }.join(", ")
706
- return_type = func[:return_type] || "void"
707
- return "**Function**\n\n```ruby\ndef #{func[:name]}(#{params}): #{return_type}\n```"
708
- end
698
+ next unless func[:name] == word
699
+
700
+ params = func[:params].map { |p| "#{p[:name]}: #{p[:type] || "untyped"}" }.join(", ")
701
+ return_type = func[:return_type] || "void"
702
+ return "**Function**\n\n```ruby\ndef #{func[:name]}(#{params}): #{return_type}\n```"
709
703
  end
710
704
 
711
705
  nil
@@ -745,34 +739,30 @@ module TRuby
745
739
  "uri" => uri,
746
740
  "range" => {
747
741
  "start" => { "line" => idx, "character" => 0 },
748
- "end" => { "line" => idx, "character" => line.length }
749
- }
742
+ "end" => { "line" => idx, "character" => line.length },
743
+ },
750
744
  }
751
745
  end
752
- end
753
746
 
754
- # Search for interface definition
755
- lines.each_with_index do |line, idx|
747
+ # Search for interface definition
756
748
  if line.match?(/^\s*interface\s+#{Regexp.escape(word)}\s*$/)
757
749
  return {
758
750
  "uri" => uri,
759
751
  "range" => {
760
752
  "start" => { "line" => idx, "character" => 0 },
761
- "end" => { "line" => idx, "character" => line.length }
762
- }
753
+ "end" => { "line" => idx, "character" => line.length },
754
+ },
763
755
  }
764
756
  end
765
- end
766
757
 
767
- # Search for function definition
768
- lines.each_with_index do |line, idx|
758
+ # Search for function definition
769
759
  if line.match?(/^\s*def\s+#{Regexp.escape(word)}\s*\(/)
770
760
  return {
771
761
  "uri" => uri,
772
762
  "range" => {
773
763
  "start" => { "line" => idx, "character" => 0 },
774
- "end" => { "line" => idx, "character" => line.length }
775
- }
764
+ "end" => { "line" => idx, "character" => line.length },
765
+ },
776
766
  }
777
767
  end
778
768
  end
@@ -794,13 +784,12 @@ module TRuby
794
784
  end
795
785
 
796
786
  def generate_semantic_tokens(text)
797
- tokens = []
798
787
  lines = text.split("\n")
799
788
 
800
789
  # Parse the document to get IR
801
790
  parser = Parser.new(text, use_combinator: true)
802
791
  parse_result = parser.parse
803
- ir_program = parser.ir_program
792
+ parser.ir_program
804
793
 
805
794
  # Collect all tokens from parsing
806
795
  raw_tokens = []
@@ -808,25 +797,25 @@ module TRuby
808
797
  # Process type aliases
809
798
  (parse_result[:type_aliases] || []).each do |alias_info|
810
799
  lines.each_with_index do |line, line_idx|
811
- if match = line.match(/^\s*type\s+(#{Regexp.escape(alias_info[:name])})\s*=/)
812
- # 'type' keyword
813
- type_pos = line.index("type")
814
- raw_tokens << [line_idx, type_pos, 4, SemanticTokenTypes::KEYWORD, SemanticTokenModifiers::DECLARATION]
800
+ next unless (match = line.match(/^\s*type\s+(#{Regexp.escape(alias_info[:name])})\s*=/))
815
801
 
816
- # Type name
817
- name_pos = match.begin(1)
818
- raw_tokens << [line_idx, name_pos, alias_info[:name].length, SemanticTokenTypes::TYPE, SemanticTokenModifiers::DEFINITION]
802
+ # 'type' keyword
803
+ type_pos = line.index("type")
804
+ raw_tokens << [line_idx, type_pos, 4, SemanticTokenTypes::KEYWORD, SemanticTokenModifiers::DECLARATION]
819
805
 
820
- # Type definition (after =)
821
- add_type_tokens(raw_tokens, line, line_idx, alias_info[:definition])
822
- end
806
+ # Type name
807
+ name_pos = match.begin(1)
808
+ raw_tokens << [line_idx, name_pos, alias_info[:name].length, SemanticTokenTypes::TYPE, SemanticTokenModifiers::DEFINITION]
809
+
810
+ # Type definition (after =)
811
+ add_type_tokens(raw_tokens, line, line_idx, alias_info[:definition])
823
812
  end
824
813
  end
825
814
 
826
815
  # Process interfaces
827
816
  (parse_result[:interfaces] || []).each do |interface_info|
828
817
  lines.each_with_index do |line, line_idx|
829
- if match = line.match(/^\s*interface\s+(#{Regexp.escape(interface_info[:name])})/)
818
+ if (match = line.match(/^\s*interface\s+(#{Regexp.escape(interface_info[:name])})/))
830
819
  # 'interface' keyword
831
820
  interface_pos = line.index("interface")
832
821
  raw_tokens << [line_idx, interface_pos, 9, SemanticTokenTypes::KEYWORD, SemanticTokenModifiers::DECLARATION]
@@ -838,13 +827,13 @@ module TRuby
838
827
 
839
828
  # Interface members
840
829
  interface_info[:members]&.each do |member|
841
- if match = line.match(/^\s*(#{Regexp.escape(member[:name])})\s*:\s*/)
842
- prop_pos = match.begin(1)
843
- raw_tokens << [line_idx, prop_pos, member[:name].length, SemanticTokenTypes::PROPERTY, 0]
830
+ next unless (match = line.match(/^\s*(#{Regexp.escape(member[:name])})\s*:\s*/))
844
831
 
845
- # Member type
846
- add_type_tokens(raw_tokens, line, line_idx, member[:type])
847
- end
832
+ prop_pos = match.begin(1)
833
+ raw_tokens << [line_idx, prop_pos, member[:name].length, SemanticTokenTypes::PROPERTY, 0]
834
+
835
+ # Member type
836
+ add_type_tokens(raw_tokens, line, line_idx, member[:type])
848
837
  end
849
838
  end
850
839
  end
@@ -852,39 +841,39 @@ module TRuby
852
841
  # Process functions
853
842
  (parse_result[:functions] || []).each do |func|
854
843
  lines.each_with_index do |line, line_idx|
855
- if match = line.match(/^\s*def\s+(#{Regexp.escape(func[:name])})\s*\(/)
856
- # 'def' keyword
857
- def_pos = line.index("def")
858
- raw_tokens << [line_idx, def_pos, 3, SemanticTokenTypes::KEYWORD, 0]
844
+ next unless (match = line.match(/^\s*def\s+(#{Regexp.escape(func[:name])})\s*\(/))
859
845
 
860
- # Function name
861
- name_pos = match.begin(1)
862
- raw_tokens << [line_idx, name_pos, func[:name].length, SemanticTokenTypes::FUNCTION, SemanticTokenModifiers::DEFINITION]
863
-
864
- # Parameters
865
- func[:params]&.each do |param|
866
- if param_match = line.match(/\b(#{Regexp.escape(param[:name])})\s*(?::\s*)?/)
867
- param_pos = param_match.begin(1)
868
- raw_tokens << [line_idx, param_pos, param[:name].length, SemanticTokenTypes::PARAMETER, 0]
869
-
870
- # Parameter type if present
871
- if param[:type]
872
- add_type_tokens(raw_tokens, line, line_idx, param[:type])
873
- end
874
- end
875
- end
846
+ # 'def' keyword
847
+ def_pos = line.index("def")
848
+ raw_tokens << [line_idx, def_pos, 3, SemanticTokenTypes::KEYWORD, 0]
849
+
850
+ # Function name
851
+ name_pos = match.begin(1)
852
+ raw_tokens << [line_idx, name_pos, func[:name].length, SemanticTokenTypes::FUNCTION, SemanticTokenModifiers::DEFINITION]
853
+
854
+ # Parameters
855
+ func[:params]&.each do |param|
856
+ next unless (param_match = line.match(/\b(#{Regexp.escape(param[:name])})\s*(?::\s*)?/))
876
857
 
877
- # Return type
878
- if func[:return_type]
879
- add_type_tokens(raw_tokens, line, line_idx, func[:return_type])
858
+ param_pos = param_match.begin(1)
859
+ raw_tokens << [line_idx, param_pos, param[:name].length, SemanticTokenTypes::PARAMETER, 0]
860
+
861
+ # Parameter type if present
862
+ if param[:type]
863
+ add_type_tokens(raw_tokens, line, line_idx, param[:type])
880
864
  end
881
865
  end
866
+
867
+ # Return type
868
+ if func[:return_type]
869
+ add_type_tokens(raw_tokens, line, line_idx, func[:return_type])
870
+ end
882
871
  end
883
872
  end
884
873
 
885
874
  # Process 'end' keywords
886
875
  lines.each_with_index do |line, line_idx|
887
- if match = line.match(/^\s*(end)\s*$/)
876
+ if (match = line.match(/^\s*(end)\s*$/))
888
877
  end_pos = match.begin(1)
889
878
  raw_tokens << [line_idx, end_pos, 3, SemanticTokenTypes::KEYWORD, 0]
890
879
  end
@@ -912,7 +901,7 @@ module TRuby
912
901
 
913
902
  # Handle generic types like Array<String>
914
903
  if type_str.include?("<")
915
- if match = type_str.match(/^(\w+)<(.+)>$/)
904
+ if (match = type_str.match(/^(\w+)<(.+)>$/))
916
905
  base = match[1]
917
906
  base_pos = line.index(base, pos)
918
907
  if base_pos
@@ -923,8 +912,9 @@ module TRuby
923
912
  # (simplified - just mark them as types)
924
913
  args = match[2]
925
914
  args.split(/[,\s]+/).each do |arg|
926
- arg = arg.strip.gsub(/[<>]/, '')
915
+ arg = arg.strip.gsub(/[<>]/, "")
927
916
  next if arg.empty?
917
+
928
918
  arg_pos = line.index(arg, pos)
929
919
  if arg_pos
930
920
  modifier = BUILT_IN_TYPES.include?(arg) ? SemanticTokenModifiers::DEFAULT_LIBRARY : 0
@@ -972,7 +962,7 @@ module TRuby
972
962
  line, char, length, token_type, modifiers = token
973
963
 
974
964
  delta_line = line - prev_line
975
- delta_char = delta_line == 0 ? char - prev_char : char
965
+ delta_char = delta_line.zero? ? char - prev_char : char
976
966
 
977
967
  encoded << delta_line
978
968
  encoded << delta_char
@@ -993,7 +983,7 @@ module TRuby
993
983
  {
994
984
  "jsonrpc" => "2.0",
995
985
  "id" => id,
996
- "result" => result
986
+ "result" => result,
997
987
  }
998
988
  end
999
989
 
@@ -1003,8 +993,8 @@ module TRuby
1003
993
  "id" => id,
1004
994
  "error" => {
1005
995
  "code" => code,
1006
- "message" => message
1007
- }
996
+ "message" => message,
997
+ },
1008
998
  }
1009
999
  end
1010
1000
  end