@@ -1770,11 +1770,11 @@ async def complete_VariablesImport( # noqa: N802
1770
1770
position : Position ,
1771
1771
context : Optional [CompletionContext ],
1772
1772
) -> Union [List [CompletionItem ], CompletionList , None ]:
1773
- from robot .parsing .lexer .tokens import Token
1774
- from robot .parsing .model .statements import VariablesImport
1773
+ from robot .parsing .lexer .tokens import Token as RobotToken
1774
+ from robot .parsing .model .statements import Statement , VariablesImport
1775
1775
1776
1776
import_node = cast (VariablesImport , node )
1777
- import_token = import_node .get_token (Token .VARIABLES )
1777
+ import_token = import_node .get_token (RobotToken .VARIABLES )
1778
1778
1779
1779
if import_token is None :
1780
1780
return []
@@ -1784,85 +1784,191 @@ async def complete_VariablesImport( # noqa: N802
1784
1784
1785
1785
import_token_index = import_node .tokens .index (import_token )
1786
1786
1787
- if len (import_node .tokens ) > import_token_index + 2 :
1788
- name_token = import_node .tokens [import_token_index + 2 ]
1789
- if not position .is_in_range (r := range_from_token (name_token )):
1790
- return None
1787
+ async def complete_import () -> Optional [List [CompletionItem ]]:
1788
+ if len (import_node .tokens ) > import_token_index + 2 :
1789
+ name_token = import_node .tokens [import_token_index + 2 ]
1790
+ if not position .is_in_range (r := range_from_token (name_token )):
1791
+ return None
1791
1792
1792
- elif len (import_node .tokens ) > import_token_index + 1 :
1793
- name_token = import_node .tokens [import_token_index + 1 ]
1794
- if position .is_in_range (r := range_from_token (name_token )):
1795
- if whitespace_at_begin_of_token (name_token ) > 1 :
1796
- ws_b = whitespace_from_begin_of_token (name_token )
1797
- r .start .character += 2 if ws_b and ws_b [0 ] != "\t " else 1
1793
+ elif len (import_node .tokens ) > import_token_index + 1 :
1794
+ name_token = import_node .tokens [import_token_index + 1 ]
1795
+ if position .is_in_range (r := range_from_token (name_token )):
1796
+ if whitespace_at_begin_of_token (name_token ) > 1 :
1797
+ ws_b = whitespace_from_begin_of_token (name_token )
1798
+ r .start .character += 2 if ws_b and ws_b [0 ] != "\t " else 1
1798
1799
1799
- if not position .is_in_range (r ):
1800
+ if not position .is_in_range (r ):
1801
+ return None
1802
+ else :
1800
1803
return None
1801
- else :
1802
- return None
1803
- else :
1804
- return None
1804
+ else :
1805
+ return None
1805
1806
1806
- pos = position .character - r .start .character
1807
- text_before_position = str (name_token .value )[:pos ].lstrip ()
1807
+ pos = position .character - r .start .character
1808
+ text_before_position = str (name_token .value )[:pos ].lstrip ()
1808
1809
1809
- if text_before_position != "" and all (c == "." for c in text_before_position ):
1810
- return None
1810
+ if text_before_position != "" and all (c == "." for c in text_before_position ):
1811
+ return None
1811
1812
1812
- last_separator_index = (
1813
- len (text_before_position )
1814
- - next ((i for i , c in enumerate (reversed (text_before_position )) if c in ["/" , os .sep ]), - 1 )
1815
- - 1
1816
- )
1813
+ last_separator_index = (
1814
+ len (text_before_position )
1815
+ - next ((i for i , c in enumerate (reversed (text_before_position )) if c in ["/" , os .sep ]), - 1 )
1816
+ - 1
1817
+ )
1817
1818
1818
- first_part = (
1819
- text_before_position [
1820
- : last_separator_index + (1 if text_before_position [last_separator_index ] in ["/" , os .sep ] else 0 )
1819
+ first_part = (
1820
+ text_before_position [
1821
+ : last_separator_index + (1 if text_before_position [last_separator_index ] in ["/" , os .sep ] else 0 )
1822
+ ]
1823
+ if last_separator_index < len (text_before_position )
1824
+ else None
1825
+ )
1826
+
1827
+ try :
1828
+ complete_list = await self .namespace .imports_manager .complete_variables_import (
1829
+ first_part if first_part else None ,
1830
+ str (self .document .uri .to_path ().parent ),
1831
+ await self .namespace .get_resolvable_variables (nodes_at_position , position ),
1832
+ )
1833
+ if not complete_list :
1834
+ return None
1835
+ except (SystemExit , KeyboardInterrupt , asyncio .CancelledError ):
1836
+ raise
1837
+ except BaseException :
1838
+ return None
1839
+
1840
+ if text_before_position == "" :
1841
+ r .start .character = position .character
1842
+ else :
1843
+ r .start .character += last_separator_index + 1 if last_separator_index < len (text_before_position ) else 0
1844
+
1845
+ return [
1846
+ CompletionItem (
1847
+ label = e .label ,
1848
+ kind = CompletionItemKind .FILE
1849
+ if e .kind in [CompleteResultKind .VARIABLES ]
1850
+ else CompletionItemKind .FILE
1851
+ if e .kind in [CompleteResultKind .FILE ]
1852
+ else CompletionItemKind .FOLDER
1853
+ if e .kind in [CompleteResultKind .FOLDER ]
1854
+ else None ,
1855
+ detail = e .kind .value ,
1856
+ sort_text = f"030_{ e } " ,
1857
+ insert_text_format = InsertTextFormat .PLAIN_TEXT ,
1858
+ text_edit = TextEdit (range = r , new_text = e .label ) if r is not None else None ,
1859
+ data = CompletionItemData (
1860
+ document_uri = str (self .document .uri ),
1861
+ type = e .kind .name ,
1862
+ name = ((first_part ) if first_part is not None else "" ) + e .label ,
1863
+ ),
1864
+ )
1865
+ for e in complete_list
1821
1866
]
1822
- if last_separator_index < len (text_before_position )
1823
- else None
1824
- )
1825
1867
1826
- try :
1827
- complete_list = await self .namespace .imports_manager .complete_variables_import (
1828
- first_part if first_part else None ,
1829
- str (self .document .uri .to_path ().parent ),
1830
- await self .namespace .get_resolvable_variables (nodes_at_position , position ),
1831
- )
1832
- if not complete_list :
1868
+ async def complete_arguments () -> Optional [List [CompletionItem ]]:
1869
+ if (
1870
+ import_node .name is None
1871
+ or position <= range_from_token (import_node .get_token (RobotToken .NAME )).extend (end_character = 1 ).end
1872
+ ):
1833
1873
return None
1834
- except (SystemExit , KeyboardInterrupt , asyncio .CancelledError ):
1835
- raise
1836
- except BaseException :
1874
+
1875
+ with_name_token = next ((v for v in import_node .tokens if v .value == "WITH NAME" ), None )
1876
+ if with_name_token is not None and position >= range_from_token (with_name_token ).start :
1877
+ return None
1878
+
1879
+ if context is None or context .trigger_kind != CompletionTriggerKind .INVOKED :
1880
+ return []
1881
+
1882
+ kw_node = cast (Statement , node )
1883
+
1884
+ tokens_at_position = get_tokens_at_position (kw_node , position )
1885
+
1886
+ if not tokens_at_position :
1887
+ return None
1888
+
1889
+ token_at_position = tokens_at_position [- 1 ]
1890
+
1891
+ if token_at_position .type not in [RobotToken .ARGUMENT , RobotToken .EOL , RobotToken .SEPARATOR ]:
1892
+ return None
1893
+
1894
+ if (
1895
+ token_at_position .type == RobotToken .EOL
1896
+ and len (tokens_at_position ) > 1
1897
+ and tokens_at_position [- 2 ].type == RobotToken .KEYWORD
1898
+ ):
1899
+ return None
1900
+
1901
+ token_at_position_index = kw_node .tokens .index (token_at_position )
1902
+
1903
+ argument_token_index = token_at_position_index
1904
+ while argument_token_index >= 0 and kw_node .tokens [argument_token_index ].type != RobotToken .ARGUMENT :
1905
+ argument_token_index -= 1
1906
+
1907
+ argument_token : Optional [RobotToken ] = None
1908
+ if argument_token_index >= 0 :
1909
+ argument_token = kw_node .tokens [argument_token_index ]
1910
+
1911
+ completion_range = range_from_token (argument_token or token_at_position )
1912
+ completion_range .end = range_from_token (token_at_position ).end
1913
+ if (w := whitespace_at_begin_of_token (token_at_position )) > 0 :
1914
+ if w > 1 and range_from_token (token_at_position ).start .character + 1 < position .character :
1915
+ completion_range .start = position
1916
+ elif completion_range .start != position :
1917
+ return None
1918
+ else :
1919
+ if "=" in (argument_token or token_at_position ).value :
1920
+ equal_index = (argument_token or token_at_position ).value .index ("=" )
1921
+ if completion_range .start .character + equal_index < position .character :
1922
+ return None
1923
+
1924
+ completion_range .end .character = completion_range .start .character + equal_index + 1
1925
+ else :
1926
+ completion_range .end = position
1927
+
1928
+ try :
1929
+ libdoc = await self .namespace .get_imported_variables_libdoc (import_node .name , import_node .args )
1930
+
1931
+ except (SystemExit , KeyboardInterrupt , asyncio .CancelledError ):
1932
+ raise
1933
+ except BaseException as e :
1934
+ self ._logger .exception (e )
1935
+ return None
1936
+
1937
+ if libdoc is not None :
1938
+ init = next ((v for v in libdoc .inits .values ()), None )
1939
+
1940
+ if init :
1941
+ return [
1942
+ CompletionItem (
1943
+ label = f"{ e .name } =" ,
1944
+ kind = CompletionItemKind .VARIABLE ,
1945
+ sort_text = f"010{ i } _{ e .name } " ,
1946
+ filter_text = e .name ,
1947
+ insert_text_format = InsertTextFormat .PLAIN_TEXT ,
1948
+ text_edit = TextEdit (range = completion_range , new_text = f"{ e .name } =" ),
1949
+ data = CompletionItemData (
1950
+ document_uri = str (self .document .uri ),
1951
+ type = "Argument" ,
1952
+ name = e .name ,
1953
+ ),
1954
+ )
1955
+ for i , e in enumerate (init .args )
1956
+ if e .kind
1957
+ not in [
1958
+ KeywordArgumentKind .VAR_POSITIONAL ,
1959
+ KeywordArgumentKind .VAR_NAMED ,
1960
+ KeywordArgumentKind .NAMED_ONLY_MARKER ,
1961
+ KeywordArgumentKind .POSITIONAL_ONLY_MARKER ,
1962
+ ]
1963
+ ]
1964
+
1837
1965
return None
1838
1966
1839
- if text_before_position == "" :
1840
- r .start .character = position .character
1841
- else :
1842
- r .start .character += last_separator_index + 1 if last_separator_index < len (text_before_position ) else 0
1967
+ result = await complete_import () or []
1968
+ # TODO this is not supported in robotframework, but it would be nice to have
1969
+ # result.extend(await complete_arguments() or [])
1843
1970
1844
- return [
1845
- CompletionItem (
1846
- label = e .label ,
1847
- kind = CompletionItemKind .FILE
1848
- if e .kind in [CompleteResultKind .VARIABLES ]
1849
- else CompletionItemKind .FILE
1850
- if e .kind in [CompleteResultKind .FILE ]
1851
- else CompletionItemKind .FOLDER
1852
- if e .kind in [CompleteResultKind .FOLDER ]
1853
- else None ,
1854
- detail = e .kind .value ,
1855
- sort_text = f"030_{ e } " ,
1856
- insert_text_format = InsertTextFormat .PLAIN_TEXT ,
1857
- text_edit = TextEdit (range = r , new_text = e .label ) if r is not None else None ,
1858
- data = CompletionItemData (
1859
- document_uri = str (self .document .uri ),
1860
- type = e .kind .name ,
1861
- name = ((first_part ) if first_part is not None else "" ) + e .label ,
1862
- ),
1863
- )
1864
- for e in complete_list
1865
- ]
1971
+ return result # noqa: RET504
1866
1972
1867
1973
async def _complete_KeywordCall_or_Fixture ( # noqa: N802
1868
1974
self ,
0 commit comments