99from loguru import logger
1010from lsap .definition import DefinitionCapability , DefinitionClient
1111from lsap .hover import HoverCapability , HoverClient
12+ from lsap .outline import OutlineCapability , OutlineClient
1213from lsap .reference import ReferenceCapability , ReferenceClient
1314from lsap .search import SearchCapability , SearchClient
1415from lsap .symbol import SymbolCapability , SymbolClient
15- from lsap .symbol_outline import SymbolOutlineCapability , SymbolOutlineClient
1616from lsap_schema .definition import DefinitionRequest
1717from lsap_schema .hover import HoverRequest
1818from lsap_schema .locate import LineScope , Locate , SymbolScope
1919from lsap_schema .models import SymbolKind
20+ from lsap_schema .outline import OutlineRequest
2021from lsap_schema .reference import ReferenceRequest
2122from lsap_schema .search import SearchRequest
2223from lsap_schema .symbol import SymbolRequest
23- from lsap_schema .symbol_outline import SymbolOutlineRequest
2424from lsp_client import Client
2525from rich .console import Console
2626from rich .markdown import Markdown
2929from lsp_cli .manager import CreateClientRequest , CreateClientResponse
3030from lsp_cli .manager .server import ManagerServer
3131from lsp_cli .server import app as server_app
32- from lsp_cli .server import get_client
32+ from lsp_cli .server import get_manager_client
3333from lsp_cli .settings import settings
3434from lsp_cli .utils .sync import cli_syncify
3535
@@ -55,7 +55,7 @@ async def init_client(path: Path) -> AsyncGenerator[Client]:
5555 console .print (f"[red]Error:[/red] No LSP client for { path } " )
5656 raise typer .Exit (1 )
5757
58- with get_client () as httpx :
58+ with get_manager_client () as httpx :
5959 req = CreateClientRequest (path = path ).model_dump (mode = "json" )
6060 resp = httpx .post ("/create" , json = req )
6161 json = resp .raise_for_status ().json ()
@@ -137,11 +137,13 @@ def main(
137137 console .print (
138138 "\n [dim]LSP CLI tool - Type [bold]--help[/bold] for more info[/dim]\n "
139139 )
140+ console .print (ctx .get_help ())
141+ raise typer .Exit ()
140142
141143
142144@app .command (
143145 "definition" ,
144- help = "Find the definition, declaration, or type definition of a symbol at a specific location . (alias: def)" ,
146+ help = "Find the definition (default) , declaration (--decl) , or type definition (--type) of a symbol. (alias: def)" ,
145147)
146148@app .command ("def" , hidden = True )
147149@cli_syncify
@@ -156,10 +158,22 @@ async def get_definition(
156158 typer .Option (
157159 "--mode" ,
158160 "-m" ,
159- help = "Search mode: 'definition' for symbol definition, 'declaration' for symbol declaration, or 'type_definition' for the type of the symbol." ,
161+ help = "Search mode (default: definition)." ,
162+ hidden = True ,
160163 ),
161164 ] = "definition" ,
165+ decl : bool = typer .Option (False , "--decl" , help = "Search for symbol declaration." ),
166+ type_def : bool = typer .Option (False , "--type" , help = "Search for type definition." ),
162167):
168+ if decl and type_def :
169+ console .print ("[red]Error:[/red] --decl and --type are mutually exclusive" )
170+ raise typer .Exit (1 )
171+
172+ if decl :
173+ mode = "declaration"
174+ elif type_def :
175+ mode = "type_definition"
176+
163177 locate = create_locate (file_path , scope , find , marker )
164178
165179 async with init_client (file_path ) as client :
@@ -175,6 +189,8 @@ async def get_definition(
175189
176190 if resp := await cap (req ):
177191 print_resp (resp , ctx )
192+ else :
193+ console .print (f"[yellow]No { mode .replace ('_' , ' ' )} found[/yellow]" )
178194
179195
180196@app .command (
@@ -201,11 +217,13 @@ async def get_hover(
201217
202218 if resp := await cap (req ):
203219 print_resp (resp , ctx )
220+ else :
221+ console .print ("[yellow]No hover information found[/yellow]" )
204222
205223
206224@app .command (
207225 "reference" ,
208- help = "Find references or implementations of a symbol at a specific location . (alias: ref)" ,
226+ help = "Find references (default) or implementations (--impl) of a symbol. (alias: ref)" ,
209227)
210228@app .command ("ref" , hidden = True )
211229@cli_syncify
@@ -220,9 +238,12 @@ async def get_reference(
220238 typer .Option (
221239 "--mode" ,
222240 "-m" ,
223- help = "Search mode: 'references' to find all usages, or 'implementations' to find concrete implementations." ,
241+ help = "Search mode (default: references)." ,
242+ hidden = True ,
224243 ),
225244 ] = "references" ,
245+ impl : bool = typer .Option (False , "--impl" , help = "Find concrete implementations." ),
246+ references : bool = typer .Option (False , "--ref" , help = "Find all usages." ),
226247 context_lines : Annotated [
227248 int ,
228249 typer .Option (
@@ -235,6 +256,15 @@ async def get_reference(
235256 start_index : op .StartIndexOpt = 0 ,
236257 pagination_id : op .PaginationIdOpt = None ,
237258):
259+ if impl and references :
260+ console .print ("[red]Error:[/red] --impl and --ref are mutually exclusive" )
261+ raise typer .Exit (1 )
262+
263+ if impl :
264+ mode = "implementations"
265+ elif references :
266+ mode = "references"
267+
238268 locate = create_locate (file_path , scope , find , marker )
239269
240270 async with init_client (file_path ) as client :
@@ -254,6 +284,8 @@ async def get_reference(
254284
255285 if resp := await cap (req ):
256286 print_resp (resp , ctx )
287+ else :
288+ console .print (f"[yellow]No { mode } found[/yellow]" )
257289
258290
259291@app .command (
@@ -263,15 +295,18 @@ async def get_reference(
263295@cli_syncify
264296async def get_outline (ctx : typer .Context , file_path : op .FileArg ):
265297 async with init_client (file_path ) as client :
266- if not isinstance (client , SymbolOutlineClient ):
298+ if not isinstance (client , OutlineClient ):
267299 console .print ("[red]Error:[/red] Client does not support symbol outline" )
268300 raise typer .Exit (1 )
269301
270- cap = SymbolOutlineCapability (client )
271- req = SymbolOutlineRequest (file_path = file_path )
302+ cap = OutlineCapability (client )
303+ req = OutlineRequest (file_path = file_path )
272304
273305 if resp := await cap (req ):
274- print_resp (resp , ctx )
306+ if resp .items :
307+ print_resp (resp , ctx )
308+ else :
309+ console .print ("[yellow]No symbols found[/yellow]" )
275310 else :
276311 console .print ("[yellow]No symbols found[/yellow]" )
277312
@@ -303,6 +338,8 @@ async def get_symbol(
303338
304339 if resp := await cap (req ):
305340 print_resp (resp , ctx )
341+ else :
342+ console .print ("[yellow]No symbol information found[/yellow]" )
306343
307344
308345@app .command (
@@ -316,7 +353,7 @@ async def search(
316353 str ,
317354 typer .Argument (help = "The name or partial name of the symbol to search for." ),
318355 ],
319- path : op .FileArg ,
356+ workspace : op .WorkspaceOpt ,
320357 kinds : Annotated [
321358 list [str ] | None ,
322359 typer .Option (
@@ -329,7 +366,7 @@ async def search(
329366 start_index : op .StartIndexOpt = 0 ,
330367 pagination_id : op .PaginationIdOpt = None ,
331368):
332- async with init_client (path ) as client :
369+ async with init_client (workspace ) as client :
333370 if not isinstance (client , SearchClient ):
334371 console .print ("[red]Error:[/red] Client does not support search" )
335372 raise typer .Exit (1 )
@@ -344,8 +381,29 @@ async def search(
344381 )
345382
346383 if resp := await cap (req ):
347- print_resp (resp , ctx )
384+ if resp .items :
385+ print_resp (resp , ctx )
386+ else :
387+ console .print ("[yellow]No matches found[/yellow]" )
388+ else :
389+ console .print ("[yellow]No matches found[/yellow]" )
390+
391+
392+ def run ():
393+ try :
394+ app ()
395+ except Exception as e :
396+ if settings .debug :
397+ raise
398+
399+ def get_msg (err : Exception ) -> str :
400+ if isinstance (err , ExceptionGroup ):
401+ return "\n " .join (get_msg (se ) for se in err .exceptions )
402+ return str (err )
403+
404+ console .print (f"[red]Error:[/red] { get_msg (e )} " )
405+ sys .exit (1 )
348406
349407
350408if __name__ == "__main__" :
351- app ()
409+ run ()
0 commit comments