@@ -14,14 +14,13 @@ use tower_lsp_server::lsp_types::{
1414 DidSaveTextDocumentParams , DocumentSymbol , DocumentSymbolParams , DocumentSymbolResponse ,
1515 ExecuteCommandParams , GotoDefinitionParams , GotoDefinitionResponse , Hover , HoverParams ,
1616 HoverProviderCapability , InitializeParams , InitializeResult , InitializedParams , Location ,
17- MarkupContent , MarkupKind , MessageType , OneOf , ParameterInformation , ParameterLabel , Range ,
18- ReferenceParams , SaveOptions , SemanticToken , SemanticTokenModifier , SemanticTokenType ,
19- SemanticTokens , SemanticTokensFullOptions , SemanticTokensLegend , SemanticTokensOptions ,
20- SemanticTokensParams , SemanticTokensResult , SemanticTokensServerCapabilities ,
21- ServerCapabilities , SignatureHelp , SignatureHelpOptions , SignatureHelpParams ,
22- SignatureInformation , SymbolKind , TextDocumentSyncCapability , TextDocumentSyncKind ,
23- TextDocumentSyncOptions , TextDocumentSyncSaveOptions , Uri , WorkDoneProgressOptions ,
24- WorkspaceFoldersServerCapabilities , WorkspaceServerCapabilities ,
17+ MarkupContent , MarkupKind , MessageType , OneOf , Range , ReferenceParams , SaveOptions ,
18+ SemanticToken , SemanticTokenModifier , SemanticTokenType , SemanticTokens ,
19+ SemanticTokensFullOptions , SemanticTokensLegend , SemanticTokensOptions , SemanticTokensParams ,
20+ SemanticTokensResult , SemanticTokensServerCapabilities , ServerCapabilities , SignatureHelp ,
21+ SignatureHelpOptions , SignatureHelpParams , SymbolKind , TextDocumentSyncCapability ,
22+ TextDocumentSyncKind , TextDocumentSyncOptions , TextDocumentSyncSaveOptions , Uri ,
23+ WorkDoneProgressOptions , WorkspaceFoldersServerCapabilities , WorkspaceServerCapabilities ,
2524} ;
2625use tower_lsp_server:: { Client , LanguageServer } ;
2726
@@ -37,7 +36,8 @@ use crate::completion::{self, CompletionProvider};
3736use crate :: error:: LspError ;
3837use crate :: function:: Functions ;
3938use crate :: utils:: {
40- find_all_references, find_function_name_range, find_related_call, get_call_span,
39+ create_signature_info, find_all_references, find_builtin_signature, find_function_call_context,
40+ find_function_name_range, find_key_position, find_related_call, get_call_span,
4141 get_comments_from_lines, position_to_span, span_contains, span_to_positions,
4242} ;
4343
@@ -854,224 +854,6 @@ fn validate_witness_file(text: &str) -> Vec<Diagnostic> {
854854 diagnostics
855855}
856856
857- /// Find the position of a key in the JSON text
858- fn find_key_position ( text : & str , key : & str ) -> Option < tower_lsp_server:: lsp_types:: Position > {
859- let search = format ! ( "\" {}\" " , key) ;
860- for ( line_num, line) in text. lines ( ) . enumerate ( ) {
861- if let Some ( col) = line. find ( & search) {
862- return Some ( tower_lsp_server:: lsp_types:: Position :: new (
863- line_num as u32 ,
864- col as u32 ,
865- ) ) ;
866- }
867- }
868- None
869- }
870-
871- /// Find the position of a value field within a witness object
872- fn find_value_position (
873- text : & str ,
874- witness_name : & str ,
875- field_name : & str ,
876- ) -> Option < tower_lsp_server:: lsp_types:: Position > {
877- let witness_search = format ! ( "\" {}\" " , witness_name) ;
878- let field_search = format ! ( "\" {}\" " , field_name) ;
879- let mut in_witness = false ;
880-
881- for ( line_num, line) in text. lines ( ) . enumerate ( ) {
882- if line. contains ( & witness_search) {
883- in_witness = true ;
884- }
885- if in_witness {
886- if let Some ( col) = line. find ( & field_search) {
887- return Some ( tower_lsp_server:: lsp_types:: Position :: new (
888- line_num as u32 ,
889- col as u32 ,
890- ) ) ;
891- }
892- // Check if we've exited the witness object (simple heuristic)
893- if line. trim ( ) == "}," || line. trim ( ) == "}" {
894- if !line. contains ( & witness_search) {
895- in_witness = false ;
896- }
897- }
898- }
899- }
900- None
901- }
902-
903- /// Find function call context from the current line.
904- /// Returns (function_name, active_parameter_index) if inside a function call.
905- fn find_function_call_context ( line : & str ) -> Option < ( String , u32 ) > {
906- let mut paren_depth = 0 ;
907- let mut bracket_depth = 0 ;
908- let mut angle_depth = 0 ;
909- let mut last_open_paren = None ;
910- let mut comma_count = 0 ;
911-
912- // Scan from the end to find the innermost unclosed function call
913- for ( i, ch) in line. chars ( ) . rev ( ) . enumerate ( ) {
914- let pos = line. len ( ) - 1 - i;
915- match ch {
916- ')' => paren_depth += 1 ,
917- '(' => {
918- if paren_depth > 0 {
919- paren_depth -= 1 ;
920- } else {
921- // Found unclosed '(' - this is our function call
922- last_open_paren = Some ( pos) ;
923- break ;
924- }
925- }
926- ']' => bracket_depth += 1 ,
927- '[' => {
928- if bracket_depth > 0 {
929- bracket_depth -= 1 ;
930- }
931- }
932- '>' => angle_depth += 1 ,
933- '<' => {
934- if angle_depth > 0 {
935- angle_depth -= 1 ;
936- }
937- }
938- ',' if paren_depth == 0 && bracket_depth == 0 && angle_depth == 0 => {
939- comma_count += 1 ;
940- }
941- _ => { }
942- }
943- }
944-
945- let open_paren_pos = last_open_paren?;
946-
947- // Extract function name before the '('
948- let before_paren = & line[ ..open_paren_pos] ;
949- let func_name = extract_function_name ( before_paren) ?;
950-
951- Some ( ( func_name, comma_count) )
952- }
953-
954- /// Extract function name from text before an opening parenthesis.
955- /// Handles patterns like: `func_name`, `jet::add_32`, `fold::<f, 8>`
956- fn extract_function_name ( text : & str ) -> Option < String > {
957- let trimmed = text. trim_end ( ) ;
958-
959- // Skip generic parameters if present (e.g., `fold::<f, 8>`)
960- let without_generics = if trimmed. ends_with ( '>' ) {
961- let mut depth = 0 ;
962- let mut start = None ;
963- for ( i, ch) in trimmed. chars ( ) . rev ( ) . enumerate ( ) {
964- match ch {
965- '>' => depth += 1 ,
966- '<' => {
967- depth -= 1 ;
968- if depth == 0 {
969- start = Some ( trimmed. len ( ) - 1 - i) ;
970- break ;
971- }
972- }
973- _ => { }
974- }
975- }
976- match start {
977- Some ( pos) => {
978- let before = & trimmed[ ..pos] ;
979- // Remove the `::` before `<` if present
980- before. strip_suffix ( "::" ) . unwrap_or ( before)
981- }
982- None => trimmed,
983- }
984- } else {
985- trimmed
986- } ;
987-
988- // Now find the function name - it should be an identifier possibly with `::`
989- let mut name_chars = Vec :: new ( ) ;
990-
991- for ch in without_generics. chars ( ) . rev ( ) {
992- if ch. is_alphanumeric ( ) || ch == '_' || ch == ':' {
993- name_chars. push ( ch) ;
994- } else {
995- break ;
996- }
997- }
998-
999- if name_chars. is_empty ( ) {
1000- return None ;
1001- }
1002-
1003- name_chars. reverse ( ) ;
1004- let name: String = name_chars. into_iter ( ) . collect ( ) ;
1005-
1006- // Clean up leading colons
1007- let cleaned = name. trim_start_matches ( ':' ) ;
1008- if cleaned. is_empty ( ) {
1009- None
1010- } else {
1011- Some ( cleaned. to_string ( ) )
1012- }
1013- }
1014-
1015- /// Create SignatureInformation from a FunctionTemplate.
1016- fn create_signature_info ( template : & completion:: types:: FunctionTemplate ) -> SignatureInformation {
1017- let params: Vec < ParameterInformation > = template
1018- . args
1019- . iter ( )
1020- . map ( |arg| ParameterInformation {
1021- label : ParameterLabel :: Simple ( arg. clone ( ) ) ,
1022- documentation : None ,
1023- } )
1024- . collect ( ) ;
1025-
1026- let signature_label = format ! (
1027- "fn {}({}) -> {}" ,
1028- template. display_name,
1029- template. args. join( ", " ) ,
1030- template. return_type
1031- ) ;
1032-
1033- SignatureInformation {
1034- label : signature_label,
1035- documentation : if template. description . is_empty ( ) {
1036- None
1037- } else {
1038- Some ( tower_lsp_server:: lsp_types:: Documentation :: MarkupContent (
1039- MarkupContent {
1040- kind : MarkupKind :: Markdown ,
1041- value : template. description . clone ( ) ,
1042- } ,
1043- ) )
1044- } ,
1045- parameters : Some ( params) ,
1046- active_parameter : None ,
1047- }
1048- }
1049-
1050- /// Find signature for builtin functions.
1051- fn find_builtin_signature ( name : & str ) -> Option < SignatureInformation > {
1052- use simplicityhl:: parse:: CallName ;
1053- use simplicityhl:: str:: AliasName ;
1054- use simplicityhl:: types:: AliasedType ;
1055-
1056- let ty = AliasedType :: from ( AliasName :: from_str_unchecked ( "T" ) ) ;
1057-
1058- // Match common builtin function names
1059- let call_name = match name {
1060- "unwrap_left" => Some ( CallName :: UnwrapLeft ( ty. clone ( ) ) ) ,
1061- "unwrap_right" => Some ( CallName :: UnwrapRight ( ty. clone ( ) ) ) ,
1062- "unwrap" => Some ( CallName :: Unwrap ) ,
1063- "is_none" => Some ( CallName :: IsNone ( ty. clone ( ) ) ) ,
1064- "assert!" => Some ( CallName :: Assert ) ,
1065- "panic!" => Some ( CallName :: Panic ) ,
1066- "dbg!" => Some ( CallName :: Debug ) ,
1067- _ => None ,
1068- } ;
1069-
1070- let call_name = call_name?;
1071- let template = completion:: builtin:: match_callname ( & call_name) ?;
1072- Some ( create_signature_info ( & template) )
1073- }
1074-
1075857#[ cfg( test) ]
1076858mod tests {
1077859 use super :: * ;
@@ -1118,78 +900,4 @@ mod tests {
1118900 ) ;
1119901 assert ! ( doc. is_none( ) , "Expected no document to return" ) ;
1120902 }
1121-
1122- #[ test]
1123- fn test_extract_function_name ( ) {
1124- // Simple function name
1125- assert_eq ! ( extract_function_name( "foo" ) , Some ( "foo" . to_string( ) ) ) ;
1126- assert_eq ! (
1127- extract_function_name( "my_func" ) ,
1128- Some ( "my_func" . to_string( ) )
1129- ) ;
1130-
1131- // With module prefix
1132- assert_eq ! (
1133- extract_function_name( "jet::add_32" ) ,
1134- Some ( "jet::add_32" . to_string( ) )
1135- ) ;
1136-
1137- // With generic parameters
1138- assert_eq ! (
1139- extract_function_name( "fold::<f, 8>" ) ,
1140- Some ( "fold" . to_string( ) )
1141- ) ;
1142- assert_eq ! (
1143- extract_function_name( "unwrap_left::<u8>" ) ,
1144- Some ( "unwrap_left" . to_string( ) )
1145- ) ;
1146-
1147- // With leading whitespace/expressions
1148- assert_eq ! (
1149- extract_function_name( "let x = foo" ) ,
1150- Some ( "foo" . to_string( ) )
1151- ) ;
1152-
1153- // Empty input
1154- assert_eq ! ( extract_function_name( "" ) , None ) ;
1155- }
1156-
1157- #[ test]
1158- fn test_find_function_call_context ( ) {
1159- // Simple function call
1160- assert_eq ! (
1161- find_function_call_context( "foo(" ) ,
1162- Some ( ( "foo" . to_string( ) , 0 ) )
1163- ) ;
1164- assert_eq ! (
1165- find_function_call_context( "foo(a, " ) ,
1166- Some ( ( "foo" . to_string( ) , 1 ) )
1167- ) ;
1168- assert_eq ! (
1169- find_function_call_context( "foo(a, b, " ) ,
1170- Some ( ( "foo" . to_string( ) , 2 ) )
1171- ) ;
1172-
1173- // Nested function calls
1174- assert_eq ! (
1175- find_function_call_context( "foo(bar(x), " ) ,
1176- Some ( ( "foo" . to_string( ) , 1 ) )
1177- ) ;
1178-
1179- // Jet function
1180- assert_eq ! (
1181- find_function_call_context( "jet::add_32(a, " ) ,
1182- Some ( ( "jet::add_32" . to_string( ) , 1 ) )
1183- ) ;
1184-
1185- // With generic parameters
1186- assert_eq ! (
1187- find_function_call_context( "fold::<f, 8>(list, " ) ,
1188- Some ( ( "fold" . to_string( ) , 1 ) )
1189- ) ;
1190-
1191- // No function call context
1192- assert_eq ! ( find_function_call_context( "let x = 5" ) , None ) ;
1193- assert_eq ! ( find_function_call_context( "" ) , None ) ;
1194- }
1195903}
0 commit comments