@@ -14,6 +14,8 @@ module lsp_server_manager_module |
| 14 | public :: send_request, send_notification | 14 | public :: send_request, send_notification |
| 15 | public :: process_server_messages | 15 | public :: process_server_messages |
| 16 | public :: register_callback | 16 | public :: register_callback |
| | 17 | + public :: get_language_for_file, start_lsp_for_file |
| | 18 | + public :: notify_file_opened, notify_file_changed, notify_file_closed |
| 17 | | 19 | |
| 18 | ! Language server configuration | 20 | ! Language server configuration |
| 19 | type :: server_config_t | 21 | type :: server_config_t |
@@ -622,4 +624,122 @@ contains |
| 622 | manager%num_callbacks = manager%num_callbacks - 1 | 624 | manager%num_callbacks = manager%num_callbacks - 1 |
| 623 | end subroutine remove_callback | 625 | end subroutine remove_callback |
| 624 | | 626 | |
| | 627 | + ! Helper to get language from filename |
| | 628 | + function get_language_for_file(filename) result(language) |
| | 629 | + character(len=*), intent(in) :: filename |
| | 630 | + character(len=:), allocatable :: language |
| | 631 | + integer :: dot_pos |
| | 632 | + |
| | 633 | + ! Find last dot in filename |
| | 634 | + dot_pos = index(filename, '.', back=.true.) |
| | 635 | + if (dot_pos == 0) then |
| | 636 | + language = "" |
| | 637 | + return |
| | 638 | + end if |
| | 639 | + |
| | 640 | + ! Match extension to language |
| | 641 | + select case(filename(dot_pos:)) |
| | 642 | + case('.py') |
| | 643 | + language = "python" |
| | 644 | + case('.rs') |
| | 645 | + language = "rust" |
| | 646 | + case('.c', '.h') |
| | 647 | + language = "c" |
| | 648 | + case('.cpp', '.cc', '.cxx', '.hpp', '.hxx', '.C', '.H') |
| | 649 | + language = "cpp" |
| | 650 | + case('.go') |
| | 651 | + language = "go" |
| | 652 | + case('.ts', '.tsx') |
| | 653 | + language = "typescript" |
| | 654 | + case('.js', '.jsx') |
| | 655 | + language = "javascript" |
| | 656 | + case('.f90', '.f95', '.f03', '.f08', '.F90', '.F95', '.F03', '.F08') |
| | 657 | + language = "fortran" |
| | 658 | + case('.java') |
| | 659 | + language = "java" |
| | 660 | + case('.rb') |
| | 661 | + language = "ruby" |
| | 662 | + case('.lua') |
| | 663 | + language = "lua" |
| | 664 | + case default |
| | 665 | + language = "" |
| | 666 | + end select |
| | 667 | + end function get_language_for_file |
| | 668 | + |
| | 669 | + ! Start LSP server for a file if needed |
| | 670 | + function start_lsp_for_file(manager, filename) result(server_index) |
| | 671 | + type(lsp_manager_t), intent(inout) :: manager |
| | 672 | + character(len=*), intent(in) :: filename |
| | 673 | + integer :: server_index |
| | 674 | + character(len=:), allocatable :: language |
| | 675 | + character(len=256) :: workspace_path |
| | 676 | + integer :: slash_pos |
| | 677 | + |
| | 678 | + server_index = 0 |
| | 679 | + |
| | 680 | + ! Get language from file extension |
| | 681 | + language = get_language_for_file(filename) |
| | 682 | + if (language == "") return |
| | 683 | + |
| | 684 | + ! Extract workspace path from filename (directory containing file) |
| | 685 | + slash_pos = index(filename, '/', back=.true.) |
| | 686 | + if (slash_pos > 0) then |
| | 687 | + workspace_path = filename(1:slash_pos-1) |
| | 688 | + else |
| | 689 | + workspace_path = "." |
| | 690 | + end if |
| | 691 | + |
| | 692 | + ! Get or start server for this language |
| | 693 | + server_index = get_or_start_server(manager, language, trim(workspace_path)) |
| | 694 | + end function start_lsp_for_file |
| | 695 | + |
| | 696 | + ! Send textDocument/didOpen notification |
| | 697 | + subroutine notify_file_opened(manager, server_index, filename, content) |
| | 698 | + use lsp_protocol_module, only: create_did_open_notification |
| | 699 | + type(lsp_manager_t), intent(inout) :: manager |
| | 700 | + integer, intent(in) :: server_index |
| | 701 | + character(len=*), intent(in) :: filename |
| | 702 | + character(len=*), intent(in) :: content |
| | 703 | + type(lsp_message_t) :: msg |
| | 704 | + character(len=:), allocatable :: language |
| | 705 | + |
| | 706 | + if (server_index < 1 .or. server_index > manager%num_servers) return |
| | 707 | + if (.not. manager%servers(server_index)%initialized) return |
| | 708 | + |
| | 709 | + language = get_language_for_file(filename) |
| | 710 | + msg = create_did_open_notification(filename, language, 1, content) |
| | 711 | + call send_notification(manager%servers(server_index), msg) |
| | 712 | + end subroutine notify_file_opened |
| | 713 | + |
| | 714 | + ! Send textDocument/didChange notification |
| | 715 | + subroutine notify_file_changed(manager, server_index, filename, content) |
| | 716 | + use lsp_protocol_module, only: create_did_change_notification |
| | 717 | + type(lsp_manager_t), intent(inout) :: manager |
| | 718 | + integer, intent(in) :: server_index |
| | 719 | + character(len=*), intent(in) :: filename |
| | 720 | + character(len=*), intent(in) :: content |
| | 721 | + type(lsp_message_t) :: msg |
| | 722 | + |
| | 723 | + if (server_index < 1 .or. server_index > manager%num_servers) return |
| | 724 | + if (.not. manager%servers(server_index)%initialized) return |
| | 725 | + |
| | 726 | + msg = create_did_change_notification(filename, 2, content) |
| | 727 | + call send_notification(manager%servers(server_index), msg) |
| | 728 | + end subroutine notify_file_changed |
| | 729 | + |
| | 730 | + ! Send textDocument/didClose notification |
| | 731 | + subroutine notify_file_closed(manager, server_index, filename) |
| | 732 | + use lsp_protocol_module, only: create_did_close_notification |
| | 733 | + type(lsp_manager_t), intent(inout) :: manager |
| | 734 | + integer, intent(in) :: server_index |
| | 735 | + character(len=*), intent(in) :: filename |
| | 736 | + type(lsp_message_t) :: msg |
| | 737 | + |
| | 738 | + if (server_index < 1 .or. server_index > manager%num_servers) return |
| | 739 | + if (.not. manager%servers(server_index)%initialized) return |
| | 740 | + |
| | 741 | + msg = create_did_close_notification(filename) |
| | 742 | + call send_notification(manager%servers(server_index), msg) |
| | 743 | + end subroutine notify_file_closed |
| | 744 | + |
| 625 | end module lsp_server_manager_module | 745 | end module lsp_server_manager_module |