lsp callback handlers ready for tests
- SHA
d3256e4a75ece88eb6045460247ebad7e20ebbcc- Parents
-
038f1e3 - Tree
c05bea0
d3256e4
d3256e4a75ece88eb6045460247ebad7e20ebbcc038f1e3
c05bea0| Status | File | + | - |
|---|---|---|---|
| M |
docs/KEYBINDINGS.md
|
12 | 11 |
| M |
docs/LSP_GUIDE.md
|
24 | 24 |
| M |
src/commands/command_handler_module.f90
|
206 | 15 |
| M |
src/lsp/lsp_server_manager_module.f90
|
19 | 16 |
| M |
src/syntax/syntax_highlighter_module.f90
|
9 | 9 |
| M |
src/terminal/input_handler_module.f90
|
130 | 32 |
| M |
src/ui/help_display_module.f90
|
5 | 1 |
| A |
test_keys.sh
|
25 | 0 |
| A |
test_raw_keys.sh
|
32 | 0 |
| A |
tests/scratch_files/README.md
|
268 | 0 |
| A |
tests/scratch_files/calculator.py
|
68 | 0 |
| A |
tests/scratch_files/main.c
|
79 | 0 |
| A |
tests/scratch_files/main.py
|
71 | 0 |
| A |
tests/scratch_files/math_utils.f90
|
89 | 0 |
| A |
tests/scratch_files/test_program.f90
|
43 | 0 |
| A |
tests/scratch_files/utils.c
|
76 | 0 |
docs/KEYBINDINGS.mdmodified@@ -8,13 +8,14 @@ Complete keyboard shortcut reference for `fac` editor. | |||
| 8 | 8 | ||
| 9 | | Keybinding | Command | Description | | 9 | | Keybinding | Command | Description | |
| 10 | |------------|---------|-------------| | 10 | |------------|---------|-------------| |
| 11 | -| `F12` | Go to Definition | Jump to where a symbol is defined | | 11 | +| `F12` or `Ctrl+\` | Go to Definition | Jump to where a symbol is defined | |
| 12 | -| `Shift+F12` | Find References | Find all usages of a symbol | | 12 | +| `Shift+F12` or `Ctrl+Shift+R` | Find References | Find all usages of a symbol | |
| 13 | | `F2` | Rename Symbol | Rename symbol across entire project | | 13 | | `F2` | Rename Symbol | Rename symbol across entire project | |
| 14 | | `Ctrl+.` | Code Actions | Quick fixes and refactorings | | 14 | | `Ctrl+.` | Code Actions | Quick fixes and refactorings | |
| 15 | -| `Ctrl+Shift+D` | Diagnostics Panel | Show all errors and warnings | | 15 | +| `F8` or `Ctrl+Shift+D` | Diagnostics Panel | Show all errors and warnings | |
| 16 | -| `Ctrl+Shift+O` | Document Symbols | Navigate symbols in current file | | 16 | +| `F4` or `Ctrl+Shift+O` | Document Symbols | Navigate symbols in current file | |
| 17 | -| `Ctrl+Shift+T` | Workspace Symbols | Search symbols across all files | | 17 | +| `F6` or `Ctrl+Shift+T` | Workspace Symbols | Search symbols across all files | |
| 18 | +| `Ctrl+P` | Command Palette | Search and execute any command | | ||
| 18 | | `Shift+Alt+F` | Format Document | Auto-format current file | | 19 | | `Shift+Alt+F` | Format Document | Auto-format current file | |
| 19 | | `Alt+,` | Jump Back | Return to previous location (jump stack) | | 20 | | `Alt+,` | Jump Back | Return to previous location (jump stack) | |
| 20 | 21 | ||
@@ -77,7 +78,7 @@ Complete keyboard shortcut reference for `fac` editor. | |||
| 77 | | `Ctrl+T` | New Tab | Create new empty tab | | 78 | | `Ctrl+T` | New Tab | Create new empty tab | |
| 78 | | `Ctrl+W` | Close Tab | Close current tab | | 79 | | `Ctrl+W` | Close Tab | Close current tab | |
| 79 | | `Ctrl+Tab` | Next Tab | Switch to next tab | | 80 | | `Ctrl+Tab` | Next Tab | Switch to next tab | |
| 80 | -| `Ctrl+Shift+Tab` | Previous Tab | Switch to previous tab | | 81 | +| `F6ab` | Previous Tab | Switch to previous tab | |
| 81 | | `Alt+1` to `Alt+9` | Jump to Tab | Switch to specific tab number | | 82 | | `Alt+1` to `Alt+9` | Jump to Tab | Switch to specific tab number | |
| 82 | | `Ctrl+\` | Split Vertical | Split current pane vertically | | 83 | | `Ctrl+\` | Split Vertical | Split current pane vertically | |
| 83 | | `Ctrl+Shift+\` | Split Horizontal | Split current pane horizontally | | 84 | | `Ctrl+Shift+\` | Split Horizontal | Split current pane horizontally | |
@@ -127,7 +128,7 @@ Complete keyboard shortcut reference for `fac` editor. | |||
| 127 | 128 | ||
| 128 | | Keybinding | Command | Description | | 129 | | Keybinding | Command | Description | |
| 129 | |------------|---------|-------------| | 130 | |------------|---------|-------------| |
| 130 | -| `Ctrl+Shift+P` | Command Palette | Search and execute any command | | 131 | +| `Ctrl+P` | Command Palette | Search and execute any command | |
| 131 | | `Ctrl+?` or `F1` | Help | Show help screen | | 132 | | `Ctrl+?` or `F1` | Help | Show help screen | |
| 132 | | `Ctrl+Shift+F` | File Tree | Toggle file explorer (Fortress mode) | | 133 | | `Ctrl+Shift+F` | File Tree | Toggle file explorer (Fortress mode) | |
| 133 | | `Esc` | Cancel/Close | Close panels, cancel operations | | 134 | | `Esc` | Cancel/Close | Close panels, cancel operations | |
@@ -218,14 +219,14 @@ Active when `Ctrl+Shift+F` is pressed: | |||
| 218 | ### Keybinding Conflicts | 219 | ### Keybinding Conflicts |
| 219 | - Some keybindings may conflict with terminal emulator shortcuts | 220 | - Some keybindings may conflict with terminal emulator shortcuts |
| 220 | - If a key doesn't work, check your terminal's keyboard settings | 221 | - If a key doesn't work, check your terminal's keyboard settings |
| 221 | -- Common conflicts: `Ctrl+Shift+T` (new terminal tab), `Ctrl+W` (close terminal tab) | 222 | +- Common conflicts: `F6` (new terminal tab), `Ctrl+W` (close terminal tab) |
| 222 | 223 | ||
| 223 | ### Customization | 224 | ### Customization |
| 224 | - Keybindings are currently hardcoded | 225 | - Keybindings are currently hardcoded |
| 225 | - Future versions will support custom keybindings | 226 | - Future versions will support custom keybindings |
| 226 | 227 | ||
| 227 | ### Discovering Commands | 228 | ### Discovering Commands |
| 228 | -- Use `Ctrl+Shift+P` (Command Palette) to see all available commands | 229 | +- Use `Ctrl+P` (Command Palette) to see all available commands |
| 229 | - Commands show their keybindings in the palette | 230 | - Commands show their keybindings in the palette |
| 230 | 231 | ||
| 231 | ### Vim Users | 232 | ### Vim Users |
@@ -242,13 +243,13 @@ Some vim-style keybindings work: | |||
| 242 | ## 🚀 Most Useful Combos | 243 | ## 🚀 Most Useful Combos |
| 243 | 244 | ||
| 244 | **Exploring code:** | 245 | **Exploring code:** |
| 245 | -1. `Ctrl+Shift+T` - Find any symbol in project | 246 | +1. `F6` - Find any symbol in project |
| 246 | 2. `F12` - Jump to definition | 247 | 2. `F12` - Jump to definition |
| 247 | 3. `Shift+F12` - See all usages | 248 | 3. `Shift+F12` - See all usages |
| 248 | 4. `Alt+,` - Jump back | 249 | 4. `Alt+,` - Jump back |
| 249 | 250 | ||
| 250 | **Fixing errors:** | 251 | **Fixing errors:** |
| 251 | -1. `Ctrl+Shift+D` - See all errors | 252 | +1. `F8` - See all errors |
| 252 | 2. Navigate to error | 253 | 2. Navigate to error |
| 253 | 3. `Ctrl+.` - Apply quick fix | 254 | 3. `Ctrl+.` - Apply quick fix |
| 254 | 4. `Ctrl+S` - Save | 255 | 4. `Ctrl+S` - Save |
docs/LSP_GUIDE.mdmodified@@ -96,7 +96,7 @@ That's it! If you have `pylsp` installed, `fac` will automatically: | |||
| 96 | ### Step 3: Try It Out | 96 | ### Step 3: Try It Out |
| 97 | 97 | ||
| 98 | 1. **See errors**: Look for `E` (error) or `W` (warning) in the left gutter | 98 | 1. **See errors**: Look for `E` (error) or `W` (warning) in the left gutter |
| 99 | -2. **View all diagnostics**: Press `Ctrl+Shift+D` to open the diagnostics panel | 99 | +2. **View all diagnostics**: Press `F8` to open the diagnostics panel |
| 100 | 3. **Jump to definition**: Put cursor on a function name and press `F12` | 100 | 3. **Jump to definition**: Put cursor on a function name and press `F12` |
| 101 | 4. **Find references**: Press `Shift+F12` to see everywhere a symbol is used | 101 | 4. **Find references**: Press `Shift+F12` to see everywhere a symbol is used |
| 102 | 5. **Rename**: Press `F2` to rename a variable across all files | 102 | 5. **Rename**: Press `F2` to rename a variable across all files |
@@ -114,7 +114,7 @@ That's it! If you have `pylsp` installed, `fac` will automatically: | |||
| 114 | - Errors appear with `E` in the gutter (red) | 114 | - Errors appear with `E` in the gutter (red) |
| 115 | - Warnings appear with `W` in the gutter (yellow) | 115 | - Warnings appear with `W` in the gutter (yellow) |
| 116 | - Put your cursor on a line with an error to see the message in the status bar | 116 | - Put your cursor on a line with an error to see the message in the status bar |
| 117 | -- Press `Ctrl+Shift+D` to open the **Diagnostics Panel** showing all issues | 117 | +- Press `F8` to open the **Diagnostics Panel** showing all issues |
| 118 | 118 | ||
| 119 | **Example:** | 119 | **Example:** |
| 120 | ```python | 120 | ```python |
@@ -125,7 +125,7 @@ def greet(name): | |||
| 125 | ``` | 125 | ``` |
| 126 | 126 | ||
| 127 | **Keybinding:** | 127 | **Keybinding:** |
| 128 | -- `Ctrl+Shift+D` - Open/close diagnostics panel | 128 | +- `F8` or `Ctrl+Shift+D` - Open/close diagnostics panel |
| 129 | - `j`/`k` or `↑`/`↓` - Navigate issues in panel | 129 | - `j`/`k` or `↑`/`↓` - Navigate issues in panel |
| 130 | - `Enter` - Jump to selected issue | 130 | - `Enter` - Jump to selected issue |
| 131 | - `Esc` - Close panel | 131 | - `Esc` - Close panel |
@@ -155,7 +155,7 @@ def calculate_total(items): # ← You land here | |||
| 155 | ``` | 155 | ``` |
| 156 | 156 | ||
| 157 | **Keybindings:** | 157 | **Keybindings:** |
| 158 | -- `F12` - Go to definition | 158 | +- `F12` or `Ctrl+\` - Go to definition |
| 159 | - `Alt+,` - Jump back (navigate backward in jump history) | 159 | - `Alt+,` - Jump back (navigate backward in jump history) |
| 160 | 160 | ||
| 161 | **Cross-file navigation:** If the definition is in another file, `fac` automatically opens it in a new tab! | 161 | **Cross-file navigation:** If the definition is in another file, `fac` automatically opens it in a new tab! |
@@ -186,7 +186,7 @@ References to 'calculate_total': | |||
| 186 | ``` | 186 | ``` |
| 187 | 187 | ||
| 188 | **Keybindings:** | 188 | **Keybindings:** |
| 189 | -- `Shift+F12` - Find all references | 189 | +- `Shift+F12` or `Ctrl+Shift+R` - Find all references |
| 190 | - `j`/`k` or `↑`/`↓` - Navigate references | 190 | - `j`/`k` or `↑`/`↓` - Navigate references |
| 191 | - `Enter` - Jump to selected reference | 191 | - `Enter` - Jump to selected reference |
| 192 | - `Esc` - Close panel | 192 | - `Esc` - Close panel |
@@ -275,12 +275,12 @@ total = calculate(10, 20) | |||
| 275 | 275 | ||
| 276 | --- | 276 | --- |
| 277 | 277 | ||
| 278 | -### 6. Document Symbols Outline (Ctrl+Shift+O) | 278 | +### 6. Document Symbols Outline (F4) |
| 279 | 279 | ||
| 280 | **What it does:** See an outline of all functions, classes, and variables in the current file. | 280 | **What it does:** See an outline of all functions, classes, and variables in the current file. |
| 281 | 281 | ||
| 282 | **How to use:** | 282 | **How to use:** |
| 283 | -1. Press `Ctrl+Shift+O` to open the symbols panel | 283 | +1. Press `F4` to open the symbols panel |
| 284 | 2. Type to filter symbols (fuzzy search) | 284 | 2. Type to filter symbols (fuzzy search) |
| 285 | 3. Press `Enter` to jump to a symbol | 285 | 3. Press `Enter` to jump to a symbol |
| 286 | 286 | ||
@@ -297,7 +297,7 @@ Document Symbols: | |||
| 297 | ``` | 297 | ``` |
| 298 | 298 | ||
| 299 | **Keybindings:** | 299 | **Keybindings:** |
| 300 | -- `Ctrl+Shift+O` - Open document symbols panel | 300 | +- `F4` or `Ctrl+Shift+O` - Open document symbols panel |
| 301 | - Type to search (fuzzy matching) | 301 | - Type to search (fuzzy matching) |
| 302 | - `j`/`k` or `↑`/`↓` - Navigate symbols | 302 | - `j`/`k` or `↑`/`↓` - Navigate symbols |
| 303 | - `Enter` - Jump to selected symbol | 303 | - `Enter` - Jump to selected symbol |
@@ -305,12 +305,12 @@ Document Symbols: | |||
| 305 | 305 | ||
| 306 | --- | 306 | --- |
| 307 | 307 | ||
| 308 | -### 7. Workspace Symbols (Ctrl+Shift+T) | 308 | +### 7. Workspace Symbols (F6) |
| 309 | 309 | ||
| 310 | **What it does:** Search for any symbol across your **entire project** (all files). | 310 | **What it does:** Search for any symbol across your **entire project** (all files). |
| 311 | 311 | ||
| 312 | **How to use:** | 312 | **How to use:** |
| 313 | -1. Press `Ctrl+Shift+T` to open workspace symbols | 313 | +1. Press `F6` to open workspace symbols |
| 314 | 2. Type part of a symbol name (fuzzy search) | 314 | 2. Type part of a symbol name (fuzzy search) |
| 315 | 3. Navigate and press `Enter` to jump to it | 315 | 3. Navigate and press `Enter` to jump to it |
| 316 | 316 | ||
@@ -331,7 +331,7 @@ Workspace Symbols: | |||
| 331 | - `calctot` matches `calculate_total` (consecutive) | 331 | - `calctot` matches `calculate_total` (consecutive) |
| 332 | 332 | ||
| 333 | **Keybindings:** | 333 | **Keybindings:** |
| 334 | -- `Ctrl+Shift+T` - Open workspace symbols | 334 | +- `F6` or `Ctrl+Shift+T` - Open workspace symbols |
| 335 | - Type to search across all files | 335 | - Type to search across all files |
| 336 | - `j`/`k` or `↑`/`↓` - Navigate results | 336 | - `j`/`k` or `↑`/`↓` - Navigate results |
| 337 | - `Enter` - Jump to symbol (opens file if needed) | 337 | - `Enter` - Jump to symbol (opens file if needed) |
@@ -414,12 +414,12 @@ def greet(name, age): | |||
| 414 | 414 | ||
| 415 | --- | 415 | --- |
| 416 | 416 | ||
| 417 | -### 10. Command Palette (Ctrl+Shift+P) | 417 | +### 10. Command Palette (Ctrl+P) |
| 418 | 418 | ||
| 419 | **What it does:** Quick access to all LSP commands without remembering keybindings. | 419 | **What it does:** Quick access to all LSP commands without remembering keybindings. |
| 420 | 420 | ||
| 421 | **How to use:** | 421 | **How to use:** |
| 422 | -1. Press `Ctrl+Shift+P` | 422 | +1. Press `Ctrl+P` |
| 423 | 2. Type to search commands (fuzzy search) | 423 | 2. Type to search commands (fuzzy search) |
| 424 | 3. Press `Enter` to execute | 424 | 3. Press `Enter` to execute |
| 425 | 425 | ||
@@ -439,7 +439,7 @@ Command Palette: | |||
| 439 | ``` | 439 | ``` |
| 440 | 440 | ||
| 441 | **Keybindings:** | 441 | **Keybindings:** |
| 442 | -- `Ctrl+Shift+P` - Open command palette | 442 | +- `Ctrl+P` - Open command palette |
| 443 | - Type to search commands | 443 | - Type to search commands |
| 444 | - `Enter` - Execute selected command | 444 | - `Enter` - Execute selected command |
| 445 | - `Esc` - Close palette | 445 | - `Esc` - Close palette |
@@ -705,14 +705,14 @@ After using F12 to jump to a definition: | |||
| 705 | ### 2. Combine Search Features | 705 | ### 2. Combine Search Features |
| 706 | 706 | ||
| 707 | - `Ctrl+F` - Search text in current file | 707 | - `Ctrl+F` - Search text in current file |
| 708 | -- `Ctrl+Shift+O` - Search symbols in current file | 708 | +- `F4` - Search symbols in current file |
| 709 | -- `Ctrl+Shift+T` - Search symbols across project | 709 | +- `F6` - Search symbols across project |
| 710 | - `Shift+F12` - Find all usages of current symbol | 710 | - `Shift+F12` - Find all usages of current symbol |
| 711 | 711 | ||
| 712 | ### 3. Fix Errors Faster | 712 | ### 3. Fix Errors Faster |
| 713 | 713 | ||
| 714 | When you see an error: | 714 | When you see an error: |
| 715 | -1. Press `Ctrl+Shift+D` to see all errors | 715 | +1. Press `F8` to see all errors |
| 716 | 2. Navigate to each error | 716 | 2. Navigate to each error |
| 717 | 3. Press `Ctrl+.` to see quick fixes | 717 | 3. Press `Ctrl+.` to see quick fixes |
| 718 | 4. Apply fixes with `Enter` | 718 | 4. Apply fixes with `Enter` |
@@ -737,15 +737,15 @@ Many language servers support format-on-save: | |||
| 737 | 737 | ||
| 738 | | Feature | Keybinding | What It Does | | 738 | | Feature | Keybinding | What It Does | |
| 739 | |---------|-----------|--------------| | 739 | |---------|-----------|--------------| |
| 740 | -| **Diagnostics Panel** | `Ctrl+Shift+D` | Show all errors/warnings | | 740 | +| **Diagnostics Panel** | `F8` or `Ctrl+Shift+D` | Show all errors/warnings | |
| 741 | -| **Go to Definition** | `F12` | Jump to where symbol is defined | | 741 | +| **Go to Definition** | `F12` or `Ctrl+\` | Jump to where symbol is defined | |
| 742 | -| **Find References** | `Shift+F12` | Find all usages of symbol | | 742 | +| **Find References** | `Shift+F12` or `Ctrl+Shift+R` | Find all usages of symbol | |
| 743 | | **Code Actions** | `Ctrl+.` | Quick fixes and refactorings | | 743 | | **Code Actions** | `Ctrl+.` | Quick fixes and refactorings | |
| 744 | | **Rename Symbol** | `F2` | Rename across entire project | | 744 | | **Rename Symbol** | `F2` | Rename across entire project | |
| 745 | -| **Document Symbols** | `Ctrl+Shift+O` | Outline of current file | | 745 | +| **Document Symbols** | `F4` or `Ctrl+Shift+O` | Outline of current file | |
| 746 | -| **Workspace Symbols** | `Ctrl+Shift+T` | Search symbols across project | | 746 | +| **Workspace Symbols** | `F6` or `Ctrl+Shift+T` | Search symbols across project | |
| 747 | | **Format Document** | `Shift+Alt+F` | Auto-format code | | 747 | | **Format Document** | `Shift+Alt+F` | Auto-format code | |
| 748 | -| **Command Palette** | `Ctrl+Shift+P` | Access all commands | | 748 | +| **Command Palette** | `Ctrl+P` | Access all commands | |
| 749 | | **Jump Back** | `Alt+,` | Return to previous location | | 749 | | **Jump Back** | `Alt+,` | Return to previous location | |
| 750 | 750 | ||
| 751 | --- | 751 | --- |
@@ -779,7 +779,7 @@ Now that you understand LSP in `fac`: | |||
| 779 | 779 | ||
| 780 | 1. **Install language servers** for your languages | 780 | 1. **Install language servers** for your languages |
| 781 | 2. **Practice the keybindings** - they'll become second nature | 781 | 2. **Practice the keybindings** - they'll become second nature |
| 782 | -3. **Explore your codebase** with `Ctrl+Shift+T` and `F12` | 782 | +3. **Explore your codebase** with `F6` and `F12` |
| 783 | 4. **Let LSP catch errors** before you run your code | 783 | 4. **Let LSP catch errors** before you run your code |
| 784 | 5. **Refactor confidently** with `F2` and `Ctrl+.` | 784 | 5. **Refactor confidently** with `F2` and `Ctrl+.` |
| 785 | 785 | ||
src/commands/command_handler_module.f90modified@@ -119,6 +119,14 @@ contains | |||
| 119 | line_count = buffer_get_line_count(buffer) | 119 | line_count = buffer_get_line_count(buffer) |
| 120 | is_edit_action = .false. | 120 | is_edit_action = .false. |
| 121 | 121 | ||
| 122 | + ! DEBUG: Log ALL keys to file only (not screen to avoid overwriting status messages) | ||
| 123 | + block | ||
| 124 | + integer :: debug_unit | ||
| 125 | + open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write') | ||
| 126 | + write(debug_unit, '(A)') '[KEY] "' // trim(key_str) // '"' | ||
| 127 | + close(debug_unit) | ||
| 128 | + end block | ||
| 129 | + | ||
| 122 | ! Ignore empty key strings (from terminal position reports, etc) | 130 | ! Ignore empty key strings (from terminal position reports, etc) |
| 123 | if (len_trim(key_str) == 0 .and. key_str(1:1) /= ' ') then | 131 | if (len_trim(key_str) == 0 .and. key_str(1:1) /= ' ') then |
| 124 | return | 132 | return |
@@ -132,10 +140,16 @@ contains | |||
| 132 | match_case_sensitive = .true. ! Reset to default | 140 | match_case_sensitive = .true. ! Reset to default |
| 133 | end if | 141 | end if |
| 134 | 142 | ||
| 135 | - ! Route input when in fuss mode (except ctrl-b/ctrl-shift-b/F2/F3 and ctrl-q which work in both modes) | 143 | + ! Route input when in fuss mode (except ctrl-b/ctrl-shift-b/F-keys/Alt-keys/ctrl-q which work in both modes) |
| 136 | if (editor%fuss_mode_active .and. trim(key_str) /= 'ctrl-b' .and. & | 144 | if (editor%fuss_mode_active .and. trim(key_str) /= 'ctrl-b' .and. & |
| 137 | trim(key_str) /= 'ctrl-shift-b' .and. trim(key_str) /= 'f2' .and. & | 145 | trim(key_str) /= 'ctrl-shift-b' .and. trim(key_str) /= 'f2' .and. & |
| 138 | - trim(key_str) /= 'f3' .and. trim(key_str) /= 'ctrl-q') then | 146 | + trim(key_str) /= 'f3' .and. trim(key_str) /= 'f4' .and. & |
| 147 | + trim(key_str) /= 'f6' .and. trim(key_str) /= 'f8' .and. & | ||
| 148 | + trim(key_str) /= 'f12' .and. trim(key_str) /= 'shift-f12' .and. & | ||
| 149 | + trim(key_str) /= 'alt-g' .and. trim(key_str) /= 'alt-o' .and. & | ||
| 150 | + trim(key_str) /= 'alt-p' .and. trim(key_str) /= 'alt-e' .and. & | ||
| 151 | + trim(key_str) /= 'alt-r' .and. trim(key_str) /= 'ctrl-\\' .and. & | ||
| 152 | + trim(key_str) /= 'ctrl-q') then | ||
| 139 | call handle_fuss_input(key_str, editor, buffer) | 153 | call handle_fuss_input(key_str, editor, buffer) |
| 140 | return | 154 | return |
| 141 | end if | 155 | end if |
@@ -1193,8 +1207,20 @@ contains | |||
| 1193 | end if | 1207 | end if |
| 1194 | end if | 1208 | end if |
| 1195 | 1209 | ||
| 1196 | - case('f12') | 1210 | + case('f12', 'ctrl-\\', 'alt-g') |
| 1197 | - ! Go to definition | 1211 | + ! Go to definition (F12, Ctrl+\, or Alt+G) |
| 1212 | + block | ||
| 1213 | + integer :: debug_unit | ||
| 1214 | + open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write') | ||
| 1215 | + write(debug_unit, '(A)') '>>> INSIDE F12/ALT-G HANDLER <<<' | ||
| 1216 | + write(debug_unit, '(A,I0)') 'active_tab_index = ', editor%active_tab_index | ||
| 1217 | + write(debug_unit, '(A,I0)') 'size(tabs) = ', size(editor%tabs) | ||
| 1218 | + if (editor%active_tab_index > 0 .and. editor%active_tab_index <= size(editor%tabs)) then | ||
| 1219 | + write(debug_unit, '(A,I0)') 'lsp_server_index = ', editor%tabs(editor%active_tab_index)%lsp_server_index | ||
| 1220 | + end if | ||
| 1221 | + close(debug_unit) | ||
| 1222 | + end block | ||
| 1223 | + call terminal_move_cursor(editor%screen_rows, 1) | ||
| 1198 | if (editor%active_tab_index > 0 .and. editor%active_tab_index <= size(editor%tabs)) then | 1224 | if (editor%active_tab_index > 0 .and. editor%active_tab_index <= size(editor%tabs)) then |
| 1199 | if (editor%tabs(editor%active_tab_index)%lsp_server_index > 0) then | 1225 | if (editor%tabs(editor%active_tab_index)%lsp_server_index > 0) then |
| 1200 | ! Save current location to jump stack | 1226 | ! Save current location to jump stack |
@@ -1211,22 +1237,40 @@ contains | |||
| 1211 | lsp_line = editor%cursors(editor%active_cursor)%line - 1 | 1237 | lsp_line = editor%cursors(editor%active_cursor)%line - 1 |
| 1212 | lsp_char = editor%cursors(editor%active_cursor)%column - 1 | 1238 | lsp_char = editor%cursors(editor%active_cursor)%column - 1 |
| 1213 | 1239 | ||
| 1240 | + ! Save editor state for callback | ||
| 1241 | + if (.not. allocated(saved_editor_for_callback)) then | ||
| 1242 | + allocate(saved_editor_for_callback) | ||
| 1243 | + end if | ||
| 1244 | + saved_editor_for_callback = editor | ||
| 1245 | + | ||
| 1214 | request_id = request_definition(editor%lsp_manager, & | 1246 | request_id = request_definition(editor%lsp_manager, & |
| 1215 | editor%tabs(editor%active_tab_index)%lsp_server_index, & | 1247 | editor%tabs(editor%active_tab_index)%lsp_server_index, & |
| 1216 | editor%tabs(editor%active_tab_index)%filename, & | 1248 | editor%tabs(editor%active_tab_index)%filename, & |
| 1217 | - lsp_line, lsp_char) | 1249 | + lsp_line, lsp_char, handle_definition_response_wrapper) |
| 1250 | + | ||
| 1251 | + block | ||
| 1252 | + integer :: debug_unit | ||
| 1253 | + open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write') | ||
| 1254 | + write(debug_unit, '(A,I0)') 'request_definition returned request_id = ', request_id | ||
| 1255 | + close(debug_unit) | ||
| 1256 | + end block | ||
| 1218 | 1257 | ||
| 1219 | if (request_id > 0) then | 1258 | if (request_id > 0) then |
| 1220 | ! Response will be handled by callback | 1259 | ! Response will be handled by callback |
| 1221 | - call terminal_move_cursor(editor%screen_rows, 1) | ||
| 1222 | call terminal_write('Searching for definition... ') | 1260 | call terminal_write('Searching for definition... ') |
| 1261 | + else | ||
| 1262 | + call terminal_write('[F12] LSP request failed ') | ||
| 1223 | end if | 1263 | end if |
| 1224 | end block | 1264 | end block |
| 1265 | + else | ||
| 1266 | + call terminal_write('[F12] No LSP server for this file ') | ||
| 1225 | end if | 1267 | end if |
| 1268 | + else | ||
| 1269 | + call terminal_write('[F12] No active tab ') | ||
| 1226 | end if | 1270 | end if |
| 1227 | 1271 | ||
| 1228 | - case('shift-f12') | 1272 | + case('shift-f12', 'alt-r') |
| 1229 | - ! Find all references | 1273 | + ! Find all references (Shift+F12 or Alt+R) |
| 1230 | if (editor%active_tab_index > 0 .and. editor%active_tab_index <= size(editor%tabs)) then | 1274 | if (editor%active_tab_index > 0 .and. editor%active_tab_index <= size(editor%tabs)) then |
| 1231 | if (editor%tabs(editor%active_tab_index)%lsp_server_index > 0) then | 1275 | if (editor%tabs(editor%active_tab_index)%lsp_server_index > 0) then |
| 1232 | ! Request references at current cursor position | 1276 | ! Request references at current cursor position |
@@ -1339,8 +1383,14 @@ contains | |||
| 1339 | end if | 1383 | end if |
| 1340 | end if | 1384 | end if |
| 1341 | 1385 | ||
| 1342 | - case('ctrl-shift-o') | 1386 | + case('f4', 'alt-o') |
| 1343 | - ! Document symbols outline | 1387 | + ! Document symbols outline (F4 or Alt+O) |
| 1388 | + block | ||
| 1389 | + integer :: debug_unit | ||
| 1390 | + open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write') | ||
| 1391 | + write(debug_unit, '(A)') '>>> INSIDE F4/ALT-O HANDLER <<<' | ||
| 1392 | + close(debug_unit) | ||
| 1393 | + end block | ||
| 1344 | if (editor%active_tab_index > 0 .and. editor%active_tab_index <= size(editor%tabs)) then | 1394 | if (editor%active_tab_index > 0 .and. editor%active_tab_index <= size(editor%tabs)) then |
| 1345 | if (editor%tabs(editor%active_tab_index)%lsp_server_index > 0) then | 1395 | if (editor%tabs(editor%active_tab_index)%lsp_server_index > 0) then |
| 1346 | ! Request document symbols | 1396 | ! Request document symbols |
@@ -1369,8 +1419,9 @@ contains | |||
| 1369 | end if | 1419 | end if |
| 1370 | end if | 1420 | end if |
| 1371 | 1421 | ||
| 1372 | - case('ctrl-shift-p') | 1422 | + case('ctrl-p') |
| 1373 | - ! Command palette | 1423 | + ! Command palette (Ctrl+P - VSCode standard) |
| 1424 | + ! Note: ctrl-shift-p doesn't work - terminals can't distinguish ctrl-p from ctrl-shift-p | ||
| 1374 | block | 1425 | block |
| 1375 | use command_palette_module, only: show_command_palette_interactive | 1426 | use command_palette_module, only: show_command_palette_interactive |
| 1376 | character(len=:), allocatable :: cmd_id | 1427 | character(len=:), allocatable :: cmd_id |
@@ -1386,7 +1437,8 @@ contains | |||
| 1386 | call render_screen(buffer, editor) | 1437 | call render_screen(buffer, editor) |
| 1387 | end block | 1438 | end block |
| 1388 | 1439 | ||
| 1389 | - case('ctrl-shift-t') | 1440 | + case('f6', 'alt-p') |
| 1441 | + ! Workspace symbols (F6 or Alt+P for project) | ||
| 1390 | ! Workspace symbols (fuzzy search across project) | 1442 | ! Workspace symbols (fuzzy search across project) |
| 1391 | if (size(editor%tabs) > 0 .and. editor%active_tab_index > 0) then | 1443 | if (size(editor%tabs) > 0 .and. editor%active_tab_index > 0) then |
| 1392 | block | 1444 | block |
@@ -1525,9 +1577,22 @@ contains | |||
| 1525 | call sync_editor_to_pane(editor) | 1577 | call sync_editor_to_pane(editor) |
| 1526 | call update_viewport(editor) | 1578 | call update_viewport(editor) |
| 1527 | 1579 | ||
| 1528 | - case('ctrl-shift-d') | 1580 | + case('f8', 'alt-e') |
| 1529 | - ! Toggle diagnostics panel | 1581 | + ! Toggle diagnostics panel (F8 or Alt+E for errors) |
| 1582 | + block | ||
| 1583 | + integer :: debug_unit | ||
| 1584 | + open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write') | ||
| 1585 | + write(debug_unit, '(A)') '>>> INSIDE F8/ALT-E HANDLER <<<' | ||
| 1586 | + write(debug_unit, '(A)') 'Calling toggle_diagnostics_panel...' | ||
| 1587 | + close(debug_unit) | ||
| 1588 | + end block | ||
| 1530 | call toggle_diagnostics_panel(editor) | 1589 | call toggle_diagnostics_panel(editor) |
| 1590 | + block | ||
| 1591 | + integer :: debug_unit | ||
| 1592 | + open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write') | ||
| 1593 | + write(debug_unit, '(A)') 'toggle_diagnostics_panel returned' | ||
| 1594 | + close(debug_unit) | ||
| 1595 | + end block | ||
| 1531 | 1596 | ||
| 1532 | case('alt-c') | 1597 | case('alt-c') |
| 1533 | ! Toggle case sensitivity for match mode (ctrl-d) | 1598 | ! Toggle case sensitivity for match mode (ctrl-d) |
@@ -1604,6 +1669,12 @@ contains | |||
| 1604 | end if | 1669 | end if |
| 1605 | 1670 | ||
| 1606 | case default | 1671 | case default |
| 1672 | + ! DEBUG: Show unhandled function keys | ||
| 1673 | + if (index(key_str, 'f') == 1 .or. index(key_str, 'shift-f') == 1) then | ||
| 1674 | + call terminal_move_cursor(editor%screen_rows, 1) | ||
| 1675 | + call terminal_write('[DEBUG] Unhandled key: ' // trim(key_str) // ' ') | ||
| 1676 | + end if | ||
| 1677 | + | ||
| 1607 | ! Check for mouse events | 1678 | ! Check for mouse events |
| 1608 | if (index(key_str, 'mouse-') == 1) then | 1679 | if (index(key_str, 'mouse-') == 1) then |
| 1609 | call handle_mouse_event_action(key_str, editor, buffer) | 1680 | call handle_mouse_event_action(key_str, editor, buffer) |
@@ -6395,4 +6466,124 @@ contains | |||
| 6395 | end block | 6466 | end block |
| 6396 | end subroutine navigate_to_workspace_symbol | 6467 | end subroutine navigate_to_workspace_symbol |
| 6397 | 6468 | ||
| 6469 | + ! ================================================== | ||
| 6470 | + ! LSP Definition Response Handler | ||
| 6471 | + ! ================================================== | ||
| 6472 | + | ||
| 6473 | + ! Wrapper callback for go to definition | ||
| 6474 | + subroutine handle_definition_response_wrapper(request_id, response) | ||
| 6475 | + use lsp_protocol_module, only: lsp_message_t | ||
| 6476 | + integer, intent(in) :: request_id | ||
| 6477 | + type(lsp_message_t), intent(in) :: response | ||
| 6478 | + | ||
| 6479 | + ! Call actual handler with saved editor state | ||
| 6480 | + if (allocated(saved_editor_for_callback)) then | ||
| 6481 | + call handle_definition_response_impl(saved_editor_for_callback, response) | ||
| 6482 | + end if | ||
| 6483 | + end subroutine handle_definition_response_wrapper | ||
| 6484 | + | ||
| 6485 | + ! Handle LSP textDocument/definition response | ||
| 6486 | + subroutine handle_definition_response_impl(editor, response) | ||
| 6487 | + use lsp_protocol_module, only: lsp_message_t | ||
| 6488 | + use json_module, only: json_value_t, json_get_object, json_get_string, & | ||
| 6489 | + json_get_number, json_array_size, json_get_array_element, & | ||
| 6490 | + json_has_key | ||
| 6491 | + type(editor_state_t), intent(inout) :: editor | ||
| 6492 | + type(lsp_message_t), intent(in) :: response | ||
| 6493 | + type(json_value_t) :: location_obj, range_obj, start_obj | ||
| 6494 | + character(len=:), allocatable :: uri, filepath | ||
| 6495 | + real(8) :: line_real, col_real | ||
| 6496 | + integer :: target_line, target_col, i, num_locations | ||
| 6497 | + logical :: found_file | ||
| 6498 | + | ||
| 6499 | + ! Log response for debugging | ||
| 6500 | + block | ||
| 6501 | + integer :: debug_unit | ||
| 6502 | + open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write') | ||
| 6503 | + write(debug_unit, '(A)') '>>> DEFINITION RESPONSE RECEIVED <<<' | ||
| 6504 | + close(debug_unit) | ||
| 6505 | + end block | ||
| 6506 | + | ||
| 6507 | + ! Try to treat result as array first | ||
| 6508 | + num_locations = json_array_size(response%result) | ||
| 6509 | + | ||
| 6510 | + if (num_locations > 0) then | ||
| 6511 | + ! Array of locations - take first one | ||
| 6512 | + location_obj = json_get_array_element(response%result, 0) | ||
| 6513 | + else if (json_has_key(response%result, "uri")) then | ||
| 6514 | + ! Single location object | ||
| 6515 | + location_obj = response%result | ||
| 6516 | + else | ||
| 6517 | + ! No definition found | ||
| 6518 | + call terminal_move_cursor(editor%screen_rows, 1) | ||
| 6519 | + call terminal_write('No definition found ') | ||
| 6520 | + return | ||
| 6521 | + end if | ||
| 6522 | + | ||
| 6523 | + ! Extract URI | ||
| 6524 | + uri = json_get_string(location_obj, 'uri', '') | ||
| 6525 | + if (len(uri) == 0) then | ||
| 6526 | + call terminal_move_cursor(editor%screen_rows, 1) | ||
| 6527 | + call terminal_write('Invalid definition response ') | ||
| 6528 | + return | ||
| 6529 | + end if | ||
| 6530 | + | ||
| 6531 | + ! Convert URI to filepath (remove file:// prefix) | ||
| 6532 | + if (len(uri) > 7 .and. uri(1:7) == 'file://') then | ||
| 6533 | + filepath = uri(8:) | ||
| 6534 | + else | ||
| 6535 | + filepath = uri | ||
| 6536 | + end if | ||
| 6537 | + | ||
| 6538 | + ! Get range | ||
| 6539 | + range_obj = json_get_object(location_obj, 'range') | ||
| 6540 | + start_obj = json_get_object(range_obj, 'start') | ||
| 6541 | + | ||
| 6542 | + line_real = json_get_number(start_obj, 'line', 0.0d0) | ||
| 6543 | + col_real = json_get_number(start_obj, 'character', 0.0d0) | ||
| 6544 | + | ||
| 6545 | + ! Convert from 0-based LSP to 1-based editor coordinates | ||
| 6546 | + target_line = int(line_real) + 1 | ||
| 6547 | + target_col = int(col_real) + 1 | ||
| 6548 | + | ||
| 6549 | + ! Log details | ||
| 6550 | + block | ||
| 6551 | + integer :: debug_unit | ||
| 6552 | + open(newunit=debug_unit, file='/tmp/fac_keys.log', position='append', action='write') | ||
| 6553 | + write(debug_unit, '(A)') 'File: ' // trim(filepath) | ||
| 6554 | + write(debug_unit, '(A,I0,A,I0)') 'Position: line=', target_line, ', col=', target_col | ||
| 6555 | + close(debug_unit) | ||
| 6556 | + end block | ||
| 6557 | + | ||
| 6558 | + ! Check if the file is already open in a tab | ||
| 6559 | + found_file = .false. | ||
| 6560 | + do i = 1, size(editor%tabs) | ||
| 6561 | + if (allocated(editor%tabs(i)%filename)) then | ||
| 6562 | + if (trim(editor%tabs(i)%filename) == trim(filepath)) then | ||
| 6563 | + ! Switch to this tab | ||
| 6564 | + editor%active_tab_index = i | ||
| 6565 | + found_file = .true. | ||
| 6566 | + exit | ||
| 6567 | + end if | ||
| 6568 | + end if | ||
| 6569 | + end do | ||
| 6570 | + | ||
| 6571 | + ! If file not found in tabs, report location | ||
| 6572 | + if (.not. found_file) then | ||
| 6573 | + call terminal_move_cursor(editor%screen_rows, 1) | ||
| 6574 | + call terminal_write('Found in: ' // trim(filepath) // ' ') | ||
| 6575 | + return | ||
| 6576 | + end if | ||
| 6577 | + | ||
| 6578 | + ! Jump to the line and column in current tab | ||
| 6579 | + editor%cursors(editor%active_cursor)%line = target_line | ||
| 6580 | + editor%cursors(editor%active_cursor)%column = target_col | ||
| 6581 | + | ||
| 6582 | + ! Center viewport on target | ||
| 6583 | + editor%viewport_line = max(1, target_line - editor%screen_rows / 2) | ||
| 6584 | + | ||
| 6585 | + call terminal_move_cursor(editor%screen_rows, 1) | ||
| 6586 | + call terminal_write('Jumped to definition ') | ||
| 6587 | + end subroutine handle_definition_response_impl | ||
| 6588 | + | ||
| 6398 | end module command_handler_module | 6589 | end module command_handler_module |
src/lsp/lsp_server_manager_module.f90modified@@ -325,21 +325,24 @@ contains | |||
| 325 | server%process_id = -1 | 325 | server%process_id = -1 |
| 326 | end subroutine stop_server | 326 | end subroutine stop_server |
| 327 | 327 | ||
| 328 | - subroutine send_request(server, msg, callback) | 328 | + subroutine send_request(manager, server_index, msg, callback) |
| 329 | - type(lsp_server_t), intent(inout) :: server | 329 | + type(lsp_manager_t), intent(inout) :: manager |
| 330 | + integer, intent(in) :: server_index | ||
| 330 | type(lsp_message_t), intent(in) :: msg | 331 | type(lsp_message_t), intent(in) :: msg |
| 331 | procedure(response_callback), optional :: callback | 332 | procedure(response_callback), optional :: callback |
| 332 | character(len=:), allocatable :: json_msg | 333 | character(len=:), allocatable :: json_msg |
| 333 | 334 | ||
| 334 | - if (.not. server%initialized .and. .not. server%initializing) return | 335 | + if (server_index < 1 .or. server_index > manager%num_servers) return |
| 336 | + if (.not. manager%servers(server_index)%initialized .and. & | ||
| 337 | + .not. manager%servers(server_index)%initializing) return | ||
| 335 | 338 | ||
| 336 | json_msg = format_json_rpc(msg) | 339 | json_msg = format_json_rpc(msg) |
| 337 | - call send_raw_message(server, json_msg) | 340 | + call send_raw_message(manager%servers(server_index), json_msg) |
| 338 | 341 | ||
| 339 | ! Track request and register callback | 342 | ! Track request and register callback |
| 340 | - call track_request(server, msg%id) | 343 | + call track_request(manager%servers(server_index), msg%id) |
| 341 | if (present(callback)) then | 344 | if (present(callback)) then |
| 342 | - ! TODO: Register callback in manager | 345 | + call register_callback(manager, msg%id, callback) |
| 343 | end if | 346 | end if |
| 344 | end subroutine send_request | 347 | end subroutine send_request |
| 345 | 348 | ||
@@ -825,7 +828,7 @@ contains | |||
| 825 | msg = create_completion_request(trim(uri), line, character) | 828 | msg = create_completion_request(trim(uri), line, character) |
| 826 | request_id = msg%id | 829 | request_id = msg%id |
| 827 | 830 | ||
| 828 | - call send_request(manager%servers(server_index), msg, callback) | 831 | + call send_request(manager, server_index, msg, callback) |
| 829 | end function request_completion | 832 | end function request_completion |
| 830 | 833 | ||
| 831 | ! Request hover information at cursor position | 834 | ! Request hover information at cursor position |
@@ -850,7 +853,7 @@ contains | |||
| 850 | msg = create_hover_request(trim(uri), line, character) | 853 | msg = create_hover_request(trim(uri), line, character) |
| 851 | request_id = msg%id | 854 | request_id = msg%id |
| 852 | 855 | ||
| 853 | - call send_request(manager%servers(server_index), msg, callback) | 856 | + call send_request(manager, server_index, msg, callback) |
| 854 | end function request_hover | 857 | end function request_hover |
| 855 | 858 | ||
| 856 | ! Request definition location at cursor position | 859 | ! Request definition location at cursor position |
@@ -875,7 +878,7 @@ contains | |||
| 875 | msg = create_definition_request(uri, line, character) | 878 | msg = create_definition_request(uri, line, character) |
| 876 | request_id = msg%id | 879 | request_id = msg%id |
| 877 | 880 | ||
| 878 | - call send_request(manager%servers(server_index), msg, callback) | 881 | + call send_request(manager, server_index, msg, callback) |
| 879 | end function request_definition | 882 | end function request_definition |
| 880 | 883 | ||
| 881 | ! Request references at cursor position | 884 | ! Request references at cursor position |
@@ -901,7 +904,7 @@ contains | |||
| 901 | msg = create_references_request(uri, line, character, .true.) | 904 | msg = create_references_request(uri, line, character, .true.) |
| 902 | request_id = msg%id | 905 | request_id = msg%id |
| 903 | 906 | ||
| 904 | - call send_request(manager%servers(server_index), msg, callback) | 907 | + call send_request(manager, server_index, msg, callback) |
| 905 | end function request_references | 908 | end function request_references |
| 906 | 909 | ||
| 907 | ! Request code actions for a range | 910 | ! Request code actions for a range |
@@ -929,7 +932,7 @@ contains | |||
| 929 | msg = create_code_action_request(uri, start_line, start_char, end_line, end_char) | 932 | msg = create_code_action_request(uri, start_line, start_char, end_line, end_char) |
| 930 | request_id = msg%id | 933 | request_id = msg%id |
| 931 | 934 | ||
| 932 | - call send_request(manager%servers(server_index), msg, callback) | 935 | + call send_request(manager, server_index, msg, callback) |
| 933 | end function request_code_actions | 936 | end function request_code_actions |
| 934 | 937 | ||
| 935 | ! Request document symbols | 938 | ! Request document symbols |
@@ -954,7 +957,7 @@ contains | |||
| 954 | msg = create_document_symbols_request(uri) | 957 | msg = create_document_symbols_request(uri) |
| 955 | request_id = msg%id | 958 | request_id = msg%id |
| 956 | 959 | ||
| 957 | - call send_request(manager%servers(server_index), msg, callback) | 960 | + call send_request(manager, server_index, msg, callback) |
| 958 | end function request_document_symbols | 961 | end function request_document_symbols |
| 959 | 962 | ||
| 960 | ! Request signature help | 963 | ! Request signature help |
@@ -980,7 +983,7 @@ contains | |||
| 980 | msg = create_signature_help_request(uri, line, character) | 983 | msg = create_signature_help_request(uri, line, character) |
| 981 | request_id = msg%id | 984 | request_id = msg%id |
| 982 | 985 | ||
| 983 | - call send_request(manager%servers(server_index), msg, callback) | 986 | + call send_request(manager, server_index, msg, callback) |
| 984 | end function request_signature_help | 987 | end function request_signature_help |
| 985 | 988 | ||
| 986 | ! Request formatting | 989 | ! Request formatting |
@@ -1007,7 +1010,7 @@ contains | |||
| 1007 | msg = create_formatting_request(uri, tab_size, insert_spaces) | 1010 | msg = create_formatting_request(uri, tab_size, insert_spaces) |
| 1008 | request_id = msg%id | 1011 | request_id = msg%id |
| 1009 | 1012 | ||
| 1010 | - call send_request(manager%servers(server_index), msg, callback) | 1013 | + call send_request(manager, server_index, msg, callback) |
| 1011 | end function request_formatting | 1014 | end function request_formatting |
| 1012 | 1015 | ||
| 1013 | ! Request rename | 1016 | ! Request rename |
@@ -1034,7 +1037,7 @@ contains | |||
| 1034 | msg = create_rename_request(uri, line, character, new_name) | 1037 | msg = create_rename_request(uri, line, character, new_name) |
| 1035 | request_id = msg%id | 1038 | request_id = msg%id |
| 1036 | 1039 | ||
| 1037 | - call send_request(manager%servers(server_index), msg, callback) | 1040 | + call send_request(manager, server_index, msg, callback) |
| 1038 | end function request_rename | 1041 | end function request_rename |
| 1039 | 1042 | ||
| 1040 | ! Request workspace symbols | 1043 | ! Request workspace symbols |
@@ -1056,7 +1059,7 @@ contains | |||
| 1056 | msg = create_workspace_symbols_request(query) | 1059 | msg = create_workspace_symbols_request(query) |
| 1057 | request_id = msg%id | 1060 | request_id = msg%id |
| 1058 | 1061 | ||
| 1059 | - call send_request(manager%servers(server_index), msg, callback) | 1062 | + call send_request(manager, server_index, msg, callback) |
| 1060 | end function request_workspace_symbols | 1063 | end function request_workspace_symbols |
| 1061 | 1064 | ||
| 1062 | ! Set the diagnostics notification handler | 1065 | ! Set the diagnostics notification handler |
src/syntax/syntax_highlighter_module.f90modified@@ -54,15 +54,15 @@ module syntax_highlighter_module | |||
| 54 | end type syntax_highlighter_t | 54 | end type syntax_highlighter_t |
| 55 | 55 | ||
| 56 | ! Color mapping (ANSI escape codes) | 56 | ! Color mapping (ANSI escape codes) |
| 57 | - character(len=16), parameter :: COLOR_KEYWORD = char(27) // '[1;34m' ! Bold Blue | 57 | + character(len=*), parameter :: COLOR_KEYWORD = char(27) // '[1;34m' ! Bold Blue |
| 58 | - character(len=16), parameter :: COLOR_STRING = char(27) // '[32m' ! Green | 58 | + character(len=*), parameter :: COLOR_STRING = char(27) // '[32m' ! Green |
| 59 | - character(len=16), parameter :: COLOR_NUMBER = char(27) // '[35m' ! Magenta | 59 | + character(len=*), parameter :: COLOR_NUMBER = char(27) // '[35m' ! Magenta |
| 60 | - character(len=16), parameter :: COLOR_COMMENT = char(27) // '[90m' ! Gray | 60 | + character(len=*), parameter :: COLOR_COMMENT = char(27) // '[90m' ! Gray |
| 61 | - character(len=16), parameter :: COLOR_OPERATOR = char(27) // '[33m' ! Yellow | 61 | + character(len=*), parameter :: COLOR_OPERATOR = char(27) // '[33m' ! Yellow |
| 62 | - character(len=16), parameter :: COLOR_TYPE = char(27) // '[36m' ! Cyan | 62 | + character(len=*), parameter :: COLOR_TYPE = char(27) // '[36m' ! Cyan |
| 63 | - character(len=16), parameter :: COLOR_FUNCTION = char(27) // '[1;36m' ! Bold Cyan | 63 | + character(len=*), parameter :: COLOR_FUNCTION = char(27) // '[1;36m' ! Bold Cyan |
| 64 | - character(len=16), parameter :: COLOR_PREPROC = char(27) // '[95m' ! Light Magenta | 64 | + character(len=*), parameter :: COLOR_PREPROC = char(27) // '[95m' ! Light Magenta |
| 65 | - character(len=16), parameter :: COLOR_RESET = char(27) // '[0m' | 65 | + character(len=*), parameter :: COLOR_RESET = char(27) // '[0m' |
| 66 | 66 | ||
| 67 | contains | 67 | contains |
| 68 | 68 | ||
src/terminal/input_handler_module.f90modified@@ -194,27 +194,34 @@ contains | |||
| 194 | end if | 194 | end if |
| 195 | else if (ch3 == '1' .or. ch3 == '2' .or. ch3 == '3' .or. ch3 == '4' .or. & | 195 | else if (ch3 == '1' .or. ch3 == '2' .or. ch3 == '3' .or. ch3 == '4' .or. & |
| 196 | ch3 == '5' .or. ch3 == '7' .or. ch3 == '8' .or. ch3 == '9') then | 196 | ch3 == '5' .or. ch3 == '7' .or. ch3 == '8' .or. ch3 == '9') then |
| 197 | - ! Function keys F1-F9: ESC [ 1 X ~ | 197 | + ! Function keys F1-F8: ESC [ 1 X ~ or ESC [ 1 X ; modifier ~ |
| 198 | char_code = terminal_read_char() | 198 | char_code = terminal_read_char() |
| 199 | - if (char_code >= 0 .and. achar(char_code) == '~') then | 199 | + if (char_code >= 0) then |
| 200 | - select case(ch3) | 200 | + ch = achar(char_code) |
| 201 | - case('1') | 201 | + if (ch == '~') then |
| 202 | - key_str = 'f1' | 202 | + ! Unmodified F1-F8 |
| 203 | - case('2') | 203 | + select case(ch3) |
| 204 | - key_str = 'f2' | 204 | + case('1') |
| 205 | - case('3') | 205 | + key_str = 'f1' |
| 206 | - key_str = 'f3' | 206 | + case('2') |
| 207 | - case('4') | 207 | + key_str = 'f2' |
| 208 | - key_str = 'f4' | 208 | + case('3') |
| 209 | - case('5') | 209 | + key_str = 'f3' |
| 210 | - key_str = 'f5' | 210 | + case('4') |
| 211 | - case('7') | 211 | + key_str = 'f4' |
| 212 | - key_str = 'f6' | 212 | + case('5') |
| 213 | - case('8') | 213 | + key_str = 'f5' |
| 214 | - key_str = 'f7' | 214 | + case('7') |
| 215 | - case('9') | 215 | + key_str = 'f6' |
| 216 | - key_str = 'f8' | 216 | + case('8') |
| 217 | - end select | 217 | + key_str = 'f7' |
| 218 | + case('9') | ||
| 219 | + key_str = 'f8' | ||
| 220 | + end select | ||
| 221 | + else if (ch == ';') then | ||
| 222 | + ! Modified F1-F8: ESC [ 1 X ; modifier ~ | ||
| 223 | + call handle_modified_function_key(key_str, '1', ch3) | ||
| 224 | + end if | ||
| 218 | end if | 225 | end if |
| 219 | else if (ch3 == ';') then | 226 | else if (ch3 == ';') then |
| 220 | ! Modified arrow key or home/end: ESC [ 1 ; 2 A format | 227 | ! Modified arrow key or home/end: ESC [ 1 ; 2 A format |
@@ -227,19 +234,26 @@ contains | |||
| 227 | if (char_code >= 0) then | 234 | if (char_code >= 0) then |
| 228 | ch3 = achar(char_code) | 235 | ch3 = achar(char_code) |
| 229 | if (ch3 == '0' .or. ch3 == '1' .or. ch3 == '3' .or. ch3 == '4') then | 236 | if (ch3 == '0' .or. ch3 == '1' .or. ch3 == '3' .or. ch3 == '4') then |
| 230 | - ! Function keys F9-F12: ESC [ 2 X ~ | 237 | + ! Function keys F9-F12: ESC [ 2 X ~ or ESC [ 2 X ; modifier ~ |
| 231 | char_code = terminal_read_char() | 238 | char_code = terminal_read_char() |
| 232 | - if (char_code >= 0 .and. achar(char_code) == '~') then | 239 | + if (char_code >= 0) then |
| 233 | - select case(ch3) | 240 | + ch = achar(char_code) |
| 234 | - case('0') | 241 | + if (ch == '~') then |
| 235 | - key_str = 'f9' | 242 | + ! Unmodified F9-F12 |
| 236 | - case('1') | 243 | + select case(ch3) |
| 237 | - key_str = 'f10' | 244 | + case('0') |
| 238 | - case('3') | 245 | + key_str = 'f9' |
| 239 | - key_str = 'f11' | 246 | + case('1') |
| 240 | - case('4') | 247 | + key_str = 'f10' |
| 241 | - key_str = 'f12' | 248 | + case('3') |
| 242 | - end select | 249 | + key_str = 'f11' |
| 250 | + case('4') | ||
| 251 | + key_str = 'f12' | ||
| 252 | + end select | ||
| 253 | + else if (ch == ';') then | ||
| 254 | + ! Modified F9-F12: ESC [ 2 X ; modifier ~ | ||
| 255 | + call handle_modified_function_key(key_str, '2', ch3) | ||
| 256 | + end if | ||
| 243 | end if | 257 | end if |
| 244 | else if (ch3 == ';') then | 258 | else if (ch3 == ';') then |
| 245 | ! ESC [ 2 ; A format (shift+arrow) | 259 | ! ESC [ 2 ; A format (shift+arrow) |
@@ -662,6 +676,90 @@ contains | |||
| 662 | end if | 676 | end if |
| 663 | end subroutine handle_modified_special_key | 677 | end subroutine handle_modified_special_key |
| 664 | 678 | ||
| 679 | + subroutine handle_modified_function_key(key_str, series, fkey_code) | ||
| 680 | + character(len=*), intent(out) :: key_str | ||
| 681 | + character, intent(in) :: series ! '1' for ESC[1X~, '2' for ESC[2X~ | ||
| 682 | + character, intent(in) :: fkey_code ! The X in ESC[1X~ or ESC[2X~ | ||
| 683 | + character :: ch, modifier_ch | ||
| 684 | + integer :: char_code, modifier | ||
| 685 | + character(len=10) :: base_key | ||
| 686 | + | ||
| 687 | + key_str = '' | ||
| 688 | + | ||
| 689 | + ! Determine base function key from series and code | ||
| 690 | + if (series == '1') then | ||
| 691 | + ! ESC[1X~ format: 1=F1, 2=F2, 3=F3, 4=F4, 5=F5, 7=F6, 8=F7, 9=F8 | ||
| 692 | + select case(fkey_code) | ||
| 693 | + case('1') | ||
| 694 | + base_key = 'f1' | ||
| 695 | + case('2') | ||
| 696 | + base_key = 'f2' | ||
| 697 | + case('3') | ||
| 698 | + base_key = 'f3' | ||
| 699 | + case('4') | ||
| 700 | + base_key = 'f4' | ||
| 701 | + case('5') | ||
| 702 | + base_key = 'f5' | ||
| 703 | + case('7') | ||
| 704 | + base_key = 'f6' | ||
| 705 | + case('8') | ||
| 706 | + base_key = 'f7' | ||
| 707 | + case('9') | ||
| 708 | + base_key = 'f8' | ||
| 709 | + case default | ||
| 710 | + return | ||
| 711 | + end select | ||
| 712 | + else if (series == '2') then | ||
| 713 | + ! ESC[2X~ format: 0=F9, 1=F10, 3=F11, 4=F12 | ||
| 714 | + select case(fkey_code) | ||
| 715 | + case('0') | ||
| 716 | + base_key = 'f9' | ||
| 717 | + case('1') | ||
| 718 | + base_key = 'f10' | ||
| 719 | + case('3') | ||
| 720 | + base_key = 'f11' | ||
| 721 | + case('4') | ||
| 722 | + base_key = 'f12' | ||
| 723 | + case default | ||
| 724 | + return | ||
| 725 | + end select | ||
| 726 | + else | ||
| 727 | + return | ||
| 728 | + end if | ||
| 729 | + | ||
| 730 | + ! Read modifier (should be a digit 2-8) | ||
| 731 | + char_code = terminal_read_char() | ||
| 732 | + if (char_code < 0) return | ||
| 733 | + modifier_ch = achar(char_code) | ||
| 734 | + | ||
| 735 | + ! Read terminating ~ | ||
| 736 | + char_code = terminal_read_char() | ||
| 737 | + if (char_code < 0 .or. achar(char_code) /= '~') return | ||
| 738 | + | ||
| 739 | + ! Parse modifier: 2=Shift, 3=Alt, 4=Alt+Shift, 5=Ctrl, 6=Ctrl+Shift, 7=Alt+Ctrl, 8=Alt+Shift | ||
| 740 | + read(modifier_ch, '(i1)') modifier | ||
| 741 | + | ||
| 742 | + select case(modifier) | ||
| 743 | + case(2) ! Shift | ||
| 744 | + key_str = 'shift-' // trim(base_key) | ||
| 745 | + case(3) ! Alt | ||
| 746 | + key_str = 'alt-' // trim(base_key) | ||
| 747 | + case(4) ! Alt+Shift | ||
| 748 | + key_str = 'alt-shift-' // trim(base_key) | ||
| 749 | + case(5) ! Ctrl | ||
| 750 | + key_str = 'ctrl-' // trim(base_key) | ||
| 751 | + case(6) ! Ctrl+Shift | ||
| 752 | + key_str = 'ctrl-shift-' // trim(base_key) | ||
| 753 | + case(7) ! Alt+Ctrl | ||
| 754 | + key_str = 'alt-ctrl-' // trim(base_key) | ||
| 755 | + case(8) ! Alt+Ctrl+Shift | ||
| 756 | + key_str = 'alt-ctrl-shift-' // trim(base_key) | ||
| 757 | + case default | ||
| 758 | + ! Unknown modifier, return unmodified key | ||
| 759 | + key_str = trim(base_key) | ||
| 760 | + end select | ||
| 761 | + end subroutine handle_modified_function_key | ||
| 762 | + | ||
| 665 | subroutine handle_mouse_event(key_str) | 763 | subroutine handle_mouse_event(key_str) |
| 666 | character(len=*), intent(out) :: key_str | 764 | character(len=*), intent(out) :: key_str |
| 667 | character :: ch | 765 | character :: ch |
src/ui/help_display_module.f90modified@@ -248,7 +248,11 @@ contains | |||
| 248 | lines(i) = " F12 go to definition"; i = i + 1 | 248 | lines(i) = " F12 go to definition"; i = i + 1 |
| 249 | lines(i) = " shift-F12 find all references"; i = i + 1 | 249 | lines(i) = " shift-F12 find all references"; i = i + 1 |
| 250 | lines(i) = " alt-, (alt-comma) jump back (navigation history)"; i = i + 1 | 250 | lines(i) = " alt-, (alt-comma) jump back (navigation history)"; i = i + 1 |
| 251 | - lines(i) = " ctrl-shift-d toggle diagnostics panel"; i = i + 1 | 251 | + lines(i) = " F2 rename symbol"; i = i + 1 |
| 252 | + lines(i) = " F4 document symbols (outline)"; i = i + 1 | ||
| 253 | + lines(i) = " F6 workspace symbols (search project)"; i = i + 1 | ||
| 254 | + lines(i) = " F8 toggle diagnostics panel (errors)"; i = i + 1 | ||
| 255 | + lines(i) = " ctrl-p command palette"; i = i + 1 | ||
| 252 | lines(i) = ""; i = i + 1 | 256 | lines(i) = ""; i = i + 1 |
| 253 | 257 | ||
| 254 | n_lines = i - 1 | 258 | n_lines = i - 1 |
test_keys.shadded@@ -0,0 +1,25 @@ | |||
| 1 | +#!/bin/bash | ||
| 2 | +# Test what escape sequences the terminal sends for function keys | ||
| 3 | + | ||
| 4 | +echo "Press keys to see their escape sequences (Ctrl+C to quit):" | ||
| 5 | +echo "Try: F12, Shift-F12, F8, F4, F6, F2" | ||
| 6 | +echo "" | ||
| 7 | + | ||
| 8 | +# Read raw input and show escape sequences | ||
| 9 | +while true; do | ||
| 10 | + read -rsn1 char | ||
| 11 | + if [[ $char == $'\e' ]]; then | ||
| 12 | + # Start of escape sequence | ||
| 13 | + seq="$char" | ||
| 14 | + # Read the rest quickly | ||
| 15 | + while read -rsn1 -t 0.001 char; do | ||
| 16 | + seq="$seq$char" | ||
| 17 | + done | ||
| 18 | + # Show it in a readable format | ||
| 19 | + echo -n "Escape sequence: " | ||
| 20 | + echo -n "$seq" | od -An -tx1 | tr -d ' \n' | ||
| 21 | + echo " (raw: $(echo -n "$seq" | cat -v))" | ||
| 22 | + else | ||
| 23 | + echo "Character: '$char' (ASCII: $(printf '%d' "'$char"))" | ||
| 24 | + fi | ||
| 25 | +done | ||
test_raw_keys.shadded@@ -0,0 +1,32 @@ | |||
| 1 | +#!/bin/bash | ||
| 2 | +# Test what escape sequences WezTerm actually sends for F-keys | ||
| 3 | +# Press F8, F12, Shift-F12, etc. and see what comes through | ||
| 4 | + | ||
| 5 | +echo "=== Raw Key Sequence Tester ===" | ||
| 6 | +echo "Press F8, F12, or Shift-F12, then Ctrl+C to exit" | ||
| 7 | +echo "This will show the EXACT escape sequences received" | ||
| 8 | +echo "" | ||
| 9 | + | ||
| 10 | +# Use od to show the raw bytes of each key press | ||
| 11 | +while true; do | ||
| 12 | + echo -n "Press a key: " | ||
| 13 | + # Read one key sequence with timeout | ||
| 14 | + IFS= read -rsn1 char | ||
| 15 | + | ||
| 16 | + # If it's ESC, read the rest of the sequence | ||
| 17 | + if [ "$char" = $'\x1b' ]; then | ||
| 18 | + # Read the next character(s) quickly | ||
| 19 | + rest="" | ||
| 20 | + while IFS= read -rsn1 -t 0.01 c; do | ||
| 21 | + rest="$rest$c" | ||
| 22 | + done | ||
| 23 | + full="$char$rest" | ||
| 24 | + | ||
| 25 | + # Show as hex and as escaped string | ||
| 26 | + echo -n "$full" | od -An -tx1 | tr -d ' \n' | ||
| 27 | + echo -n " = ESC" | ||
| 28 | + echo "$rest" | sed 's/./[&]/g' | ||
| 29 | + else | ||
| 30 | + echo "$char" | ||
| 31 | + fi | ||
| 32 | +done | ||
tests/scratch_files/README.mdadded@@ -0,0 +1,268 @@ | |||
| 1 | +# LSP Feature Test Files | ||
| 2 | + | ||
| 3 | +These files are designed to test all LSP features in `fac`. Each file contains intentional errors and cross-references for comprehensive testing. | ||
| 4 | + | ||
| 5 | +## Files Overview | ||
| 6 | + | ||
| 7 | +### Python Files | ||
| 8 | +- **calculator.py** - Math functions with intentional errors | ||
| 9 | + - Undefined variable errors (`reslt` instead of `result`) | ||
| 10 | + - Missing import errors (`math` module) | ||
| 11 | + - Multiple functions for testing navigation | ||
| 12 | + | ||
| 13 | +- **main.py** - Main program importing calculator | ||
| 14 | + - Cross-file references for testing F12 | ||
| 15 | + - Class structure for Document Symbols | ||
| 16 | + - Missing import error (`divide` function) | ||
| 17 | + | ||
| 18 | +### Fortran Files | ||
| 19 | +- **math_utils.f90** - Math utilities module | ||
| 20 | + - Vector operations (add, dot product, magnitude) | ||
| 21 | + - Matrix multiplication | ||
| 22 | + - Intentional errors (uninitialized variables) | ||
| 23 | + | ||
| 24 | +- **test_program.f90** - Program using math_utils | ||
| 25 | + - Cross-file references to test F12 | ||
| 26 | + - Undefined variable error | ||
| 27 | + | ||
| 28 | +### C Files | ||
| 29 | +- **utils.c** - Utility functions | ||
| 30 | + - Factorial, fibonacci, array operations | ||
| 31 | + - Intentional errors (undefined variables, type mismatches) | ||
| 32 | + | ||
| 33 | +- **main.c** - Main program using utils | ||
| 34 | + - Cross-file function calls | ||
| 35 | + - Structure definition | ||
| 36 | + - Multiple intentional errors | ||
| 37 | + | ||
| 38 | +## Testing LSP Features | ||
| 39 | + | ||
| 40 | +### 1. Diagnostics (F8) | ||
| 41 | + | ||
| 42 | +**Test:** Open any file and check for error markers in the gutter. | ||
| 43 | + | ||
| 44 | +Expected errors: | ||
| 45 | +- **calculator.py**: `reslt` undefined, `math` not imported | ||
| 46 | +- **main.py**: `divide` not imported | ||
| 47 | +- **math_utils.f90**: `undefined_var` in `broken_routine` | ||
| 48 | +- **test_program.f90**: `undefined_result` not declared | ||
| 49 | +- **utils.c**: `undefined_var`, type mismatch, missing return | ||
| 50 | +- **main.c**: `undefined_function`, type mismatch, `undeclared_var` | ||
| 51 | + | ||
| 52 | +**How to test:** | ||
| 53 | +```bash | ||
| 54 | +fac calculator.py | ||
| 55 | +# Press F8 to open diagnostics panel | ||
| 56 | +# Navigate with j/k or ↑/↓ | ||
| 57 | +# Press Enter to jump to error | ||
| 58 | +``` | ||
| 59 | + | ||
| 60 | +### 2. Go to Definition (F12) | ||
| 61 | + | ||
| 62 | +**Test:** Cross-file navigation between importing files. | ||
| 63 | + | ||
| 64 | +**In main.py:** | ||
| 65 | +1. Put cursor on `add` on line ~15 | ||
| 66 | +2. Press `F12` | ||
| 67 | +3. Should jump to `def add()` in calculator.py | ||
| 68 | + | ||
| 69 | +**In test_program.f90:** | ||
| 70 | +1. Put cursor on `vector_add` on line ~23 | ||
| 71 | +2. Press `F12` | ||
| 72 | +3. Should jump to `subroutine vector_add` in math_utils.f90 | ||
| 73 | + | ||
| 74 | +**In main.c:** | ||
| 75 | +1. Put cursor on `factorial` on line ~28 | ||
| 76 | +2. Press `F12` | ||
| 77 | +3. Should jump to `int factorial()` in utils.c | ||
| 78 | + | ||
| 79 | +**Return:** Press `Alt+,` to jump back! | ||
| 80 | + | ||
| 81 | +### 3. Find References (Shift+F12) | ||
| 82 | + | ||
| 83 | +**Test:** Find all usages of a function. | ||
| 84 | + | ||
| 85 | +**In calculator.py:** | ||
| 86 | +1. Put cursor on `calculate_total` function name | ||
| 87 | +2. Press `Shift+F12` | ||
| 88 | +3. Should show: | ||
| 89 | + - Definition in calculator.py | ||
| 90 | + - Usage in main.py (imported and called) | ||
| 91 | + | ||
| 92 | +**In math_utils.f90:** | ||
| 93 | +1. Put cursor on `vector_dot` | ||
| 94 | +2. Press `Shift+F12` | ||
| 95 | +3. Should show usage in test_program.f90 | ||
| 96 | + | ||
| 97 | +### 4. Code Actions (Ctrl+.) | ||
| 98 | + | ||
| 99 | +**Test:** Quick fixes for errors. | ||
| 100 | + | ||
| 101 | +**In calculator.py line ~48:** | ||
| 102 | +1. Put cursor on `reslt` (undefined error) | ||
| 103 | +2. Press `Ctrl+.` | ||
| 104 | +3. Should offer to fix the typo or define `reslt` | ||
| 105 | + | ||
| 106 | +**In main.py line ~45:** | ||
| 107 | +1. Put cursor on `divide` (not imported error) | ||
| 108 | +2. Press `Ctrl+.` | ||
| 109 | +3. Should offer to add `divide` to imports | ||
| 110 | + | ||
| 111 | +### 5. Rename Symbol (F2) | ||
| 112 | + | ||
| 113 | +**Test:** Rename across files. | ||
| 114 | + | ||
| 115 | +**In calculator.py:** | ||
| 116 | +1. Put cursor on `add` function name | ||
| 117 | +2. Press `F2` | ||
| 118 | +3. Type new name (e.g., `add_numbers`) | ||
| 119 | +4. Press Enter | ||
| 120 | +5. Check: | ||
| 121 | + - Function renamed in calculator.py | ||
| 122 | + - Import statement updated in main.py | ||
| 123 | + - Function call updated in main.py | ||
| 124 | + | ||
| 125 | +**Undo:** Press `Ctrl+Z` repeatedly to revert | ||
| 126 | + | ||
| 127 | +### 6. Document Symbols (F4) | ||
| 128 | + | ||
| 129 | +**Test:** See file outline. | ||
| 130 | + | ||
| 131 | +**In calculator.py:** | ||
| 132 | +1. Press `F4` | ||
| 133 | +2. Should see: | ||
| 134 | + - `add` function | ||
| 135 | + - `subtract` function | ||
| 136 | + - `multiply` function | ||
| 137 | + - `divide` function | ||
| 138 | + - etc. | ||
| 139 | +3. Type "broken" to filter | ||
| 140 | +4. Press Enter to jump to function | ||
| 141 | + | ||
| 142 | +**In main.py:** | ||
| 143 | +1. Press `F4` | ||
| 144 | +2. Should see: | ||
| 145 | + - `DataProcessor` class | ||
| 146 | + - `process_data` function | ||
| 147 | + - `main` function | ||
| 148 | + | ||
| 149 | +### 7. Workspace Symbols (F6) | ||
| 150 | + | ||
| 151 | +**Test:** Search symbols across ALL files. | ||
| 152 | + | ||
| 153 | +1. Press `F6` | ||
| 154 | +2. Type "add" | ||
| 155 | +3. Should see: | ||
| 156 | + - `add` function in calculator.py | ||
| 157 | + - `vector_add` in math_utils.f90 | ||
| 158 | + - Maybe `sum_array` in utils.c (fuzzy match) | ||
| 159 | +4. Navigate with j/k | ||
| 160 | +5. Press Enter to jump (opens file if needed) | ||
| 161 | + | ||
| 162 | +**Try different searches:** | ||
| 163 | +- "calc" → finds `calculate_total`, `calculator`, etc. | ||
| 164 | +- "vector" → finds all vector functions | ||
| 165 | +- "fact" → finds `factorial` | ||
| 166 | + | ||
| 167 | +### 8. Signature Help | ||
| 168 | + | ||
| 169 | +**Test:** Parameter hints while typing. | ||
| 170 | + | ||
| 171 | +**In any Python file:** | ||
| 172 | +1. Type: `calculate_total(` | ||
| 173 | +2. Should see tooltip: `calculate_total(items)` | ||
| 174 | +3. As you type, current parameter is highlighted | ||
| 175 | + | ||
| 176 | +**In Fortran:** | ||
| 177 | +1. Type: `call vector_add(` | ||
| 178 | +2. Should see signature with parameters | ||
| 179 | + | ||
| 180 | +### 9. Document Formatting (Shift+Alt+F) | ||
| 181 | + | ||
| 182 | +**Test:** Auto-format code. | ||
| 183 | + | ||
| 184 | +**In calculator.py:** | ||
| 185 | +1. Mess up the formatting (add extra spaces, wrong indentation) | ||
| 186 | +2. Press `Shift+Alt+F` | ||
| 187 | +3. Code should be auto-formatted to PEP 8 style | ||
| 188 | + | ||
| 189 | +**In utils.c:** | ||
| 190 | +1. Mess up braces and indentation | ||
| 191 | +2. Press `Shift+Alt+F` | ||
| 192 | +3. Code should be formatted with clang-format | ||
| 193 | + | ||
| 194 | +### 10. Command Palette (Ctrl+P) | ||
| 195 | + | ||
| 196 | +**Test:** Access commands without keybindings. | ||
| 197 | + | ||
| 198 | +1. Press `Ctrl+P` | ||
| 199 | +2. Type "format" | ||
| 200 | +3. Select "Format Document" | ||
| 201 | +4. Same as Shift+Alt+F | ||
| 202 | + | ||
| 203 | +Or: | ||
| 204 | +1. Press `Ctrl+P` | ||
| 205 | +2. Type "def" | ||
| 206 | +3. Select "Go to Definition" | ||
| 207 | +4. Same as F12 | ||
| 208 | + | ||
| 209 | +## Language Server Setup | ||
| 210 | + | ||
| 211 | +To test these files, you need language servers installed: | ||
| 212 | + | ||
| 213 | +**Python:** | ||
| 214 | +```bash | ||
| 215 | +pip install python-lsp-server | ||
| 216 | +``` | ||
| 217 | + | ||
| 218 | +**Fortran:** | ||
| 219 | +```bash | ||
| 220 | +pip install fortls | ||
| 221 | +``` | ||
| 222 | + | ||
| 223 | +**C/C++:** | ||
| 224 | +```bash | ||
| 225 | +# macOS | ||
| 226 | +brew install llvm | ||
| 227 | + | ||
| 228 | +# Linux | ||
| 229 | +sudo apt install clangd | ||
| 230 | +``` | ||
| 231 | + | ||
| 232 | +## Expected Behavior | ||
| 233 | + | ||
| 234 | +### With Language Server Installed: | ||
| 235 | +- ✅ Red/yellow error markers in gutter | ||
| 236 | +- ✅ F12 jumps to definitions (even across files) | ||
| 237 | +- ✅ Shift+F12 shows all references | ||
| 238 | +- ✅ Ctrl+. offers quick fixes | ||
| 239 | +- ✅ F2 renames across files | ||
| 240 | +- ✅ F4 shows file outline | ||
| 241 | +- ✅ F6 searches all symbols | ||
| 242 | +- ✅ Shift+Alt+F formats code | ||
| 243 | + | ||
| 244 | +### Without Language Server: | ||
| 245 | +- ❌ No error markers | ||
| 246 | +- ❌ LSP features won't work | ||
| 247 | +- ✅ Basic editing still works | ||
| 248 | +- ✅ Syntax highlighting may work (if implemented separately) | ||
| 249 | + | ||
| 250 | +## Known Issues to Test | ||
| 251 | + | ||
| 252 | +1. **Syntax highlighting for Fortran** - Check if keywords are colored | ||
| 253 | +2. **F8 vs Ctrl+D** - Check if modifier keys work correctly | ||
| 254 | +3. **Cross-file tabs** - Check if F12 opens new tabs correctly | ||
| 255 | +4. **Jump stack** - Check if Alt+, returns to previous location | ||
| 256 | + | ||
| 257 | +## Quick Test Checklist | ||
| 258 | + | ||
| 259 | +- [ ] Open calculator.py and see diagnostics (red/yellow markers) | ||
| 260 | +- [ ] Press F8 and see error list | ||
| 261 | +- [ ] F12 on `add` in main.py → jumps to calculator.py | ||
| 262 | +- [ ] Alt+, → jumps back | ||
| 263 | +- [ ] Shift+F12 on `calculate_total` → shows references | ||
| 264 | +- [ ] F2 on `multiply` → rename and see it update in both files | ||
| 265 | +- [ ] F4 → see file outline | ||
| 266 | +- [ ] F6, type "vector" → find Fortran functions | ||
| 267 | +- [ ] Ctrl+. on an error → see quick fixes | ||
| 268 | +- [ ] Shift+Alt+F → format code | ||
tests/scratch_files/calculator.pyadded@@ -0,0 +1,68 @@ | |||
| 1 | +""" | ||
| 2 | +Simple calculator module for testing LSP features. | ||
| 3 | + | ||
| 4 | +Test these features: | ||
| 5 | +- Diagnostics: See the intentional errors below | ||
| 6 | +- Go to Definition: F12 on function calls | ||
| 7 | +- Find References: Shift+F12 on function names | ||
| 8 | +- Rename: F2 on any function/variable | ||
| 9 | +- Code Actions: Ctrl+. on errors | ||
| 10 | +- Document Symbols: Ctrl+Shift+O to see outline | ||
| 11 | +- Formatting: Shift+Alt+F to format | ||
| 12 | +""" | ||
| 13 | + | ||
| 14 | +def add(x, y): | ||
| 15 | + """Add two numbers together.""" | ||
| 16 | + return x + y | ||
| 17 | + | ||
| 18 | + | ||
| 19 | +def subtract(x, y): | ||
| 20 | + """Subtract y from x.""" | ||
| 21 | + return x - y | ||
| 22 | + | ||
| 23 | + | ||
| 24 | +def multiply(x, y): | ||
| 25 | + """Multiply two numbers.""" | ||
| 26 | + return x * y | ||
| 27 | + | ||
| 28 | + | ||
| 29 | +def divide(x, y): | ||
| 30 | + """Divide x by y.""" | ||
| 31 | + if y == 0: | ||
| 32 | + raise ValueError("Cannot divide by zero") | ||
| 33 | + return x / y | ||
| 34 | + | ||
| 35 | + | ||
| 36 | +def calculate_total(items): | ||
| 37 | + """Calculate total from a list of numbers.""" | ||
| 38 | + total = 0 | ||
| 39 | + for item in items: | ||
| 40 | + total = total + item | ||
| 41 | + return total | ||
| 42 | + | ||
| 43 | + | ||
| 44 | +# Intentional error for diagnostics testing | ||
| 45 | +def broken_function(): | ||
| 46 | + """This function has an error - undefined variable.""" | ||
| 47 | + result = add(5, 3) | ||
| 48 | + print(f"Result: {reslt}") # ERROR: typo - should be 'result' | ||
| 49 | + return reslt | ||
| 50 | + | ||
| 51 | + | ||
| 52 | +# Another intentional error - missing import | ||
| 53 | +def use_math(): | ||
| 54 | + """Uses math module without importing it.""" | ||
| 55 | + return math.sqrt(16) # ERROR: 'math' is not defined | ||
| 56 | + | ||
| 57 | + | ||
| 58 | +# Test code | ||
| 59 | +if __name__ == "__main__": | ||
| 60 | + # These work fine | ||
| 61 | + print(add(10, 5)) | ||
| 62 | + print(subtract(10, 5)) | ||
| 63 | + print(multiply(10, 5)) | ||
| 64 | + print(divide(10, 5)) | ||
| 65 | + | ||
| 66 | + # This will show diagnostic errors | ||
| 67 | + broken_function() | ||
| 68 | + use_math() | ||
tests/scratch_files/main.cadded@@ -0,0 +1,79 @@ | |||
| 1 | +/* | ||
| 2 | + * Main program using utility functions | ||
| 3 | + * | ||
| 4 | + * Test cross-file navigation: | ||
| 5 | + * - F12 on 'factorial' should jump to utils.c | ||
| 6 | + * - Shift+F12 on 'fibonacci' should show all usages | ||
| 7 | + * - Ctrl+Shift+T and search "sum" to find sum_array | ||
| 8 | + */ | ||
| 9 | + | ||
| 10 | +#include <stdio.h> | ||
| 11 | + | ||
| 12 | +// Forward declarations from utils.c | ||
| 13 | +int factorial(int n); | ||
| 14 | +int fibonacci(int n); | ||
| 15 | +int sum_array(int *arr, int size); | ||
| 16 | +int find_max(int *arr, int size); | ||
| 17 | + | ||
| 18 | +// Structure for testing Document Symbols (Ctrl+Shift+O) | ||
| 19 | +typedef struct { | ||
| 20 | + int id; | ||
| 21 | + char name[50]; | ||
| 22 | + double value; | ||
| 23 | +} Record; | ||
| 24 | + | ||
| 25 | +// Test: F12 on this function name to jump to definition | ||
| 26 | +void process_records(Record *records, int count) { | ||
| 27 | + printf("Processing %d records\n", count); | ||
| 28 | + for (int i = 0; i < count; i++) { | ||
| 29 | + printf("Record %d: %s = %.2f\n", | ||
| 30 | + records[i].id, | ||
| 31 | + records[i].name, | ||
| 32 | + records[i].value); | ||
| 33 | + } | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +int main() { | ||
| 37 | + printf("Testing LSP features in C\n\n"); | ||
| 38 | + | ||
| 39 | + // Test factorial | ||
| 40 | + // F12 on 'factorial' should jump to utils.c | ||
| 41 | + int fact = factorial(5); | ||
| 42 | + printf("factorial(5) = %d\n", fact); | ||
| 43 | + | ||
| 44 | + // Test fibonacci | ||
| 45 | + // Shift+F12 on 'fibonacci' should show all usages | ||
| 46 | + int fib = fibonacci(7); | ||
| 47 | + printf("fibonacci(7) = %d\n", fib); | ||
| 48 | + | ||
| 49 | + // Test array functions | ||
| 50 | + int numbers[] = {5, 2, 8, 1, 9, 3}; | ||
| 51 | + int size = sizeof(numbers) / sizeof(numbers[0]); | ||
| 52 | + | ||
| 53 | + // F12 on 'sum_array' should jump to definition | ||
| 54 | + int total = sum_array(numbers, size); | ||
| 55 | + printf("sum_array() = %d\n", total); | ||
| 56 | + | ||
| 57 | + // F12 on 'find_max' should jump to definition | ||
| 58 | + int max = find_max(numbers, size); | ||
| 59 | + printf("find_max() = %d\n", max); | ||
| 60 | + | ||
| 61 | + // Test with records | ||
| 62 | + Record records[2] = { | ||
| 63 | + {1, "Alpha", 3.14}, | ||
| 64 | + {2, "Beta", 2.71} | ||
| 65 | + }; | ||
| 66 | + process_records(records, 2); | ||
| 67 | + | ||
| 68 | + // Intentional errors for diagnostics | ||
| 69 | + // ERROR: undefined function | ||
| 70 | + int result = undefined_function(10); | ||
| 71 | + | ||
| 72 | + // ERROR: type mismatch | ||
| 73 | + char *str = fact; | ||
| 74 | + | ||
| 75 | + // ERROR: undeclared variable | ||
| 76 | + printf("Value: %d\n", undeclared_var); | ||
| 77 | + | ||
| 78 | + return 0; | ||
| 79 | +} | ||
tests/scratch_files/main.pyadded@@ -0,0 +1,71 @@ | |||
| 1 | +""" | ||
| 2 | +Main module that uses calculator. | ||
| 3 | + | ||
| 4 | +Test cross-file navigation: | ||
| 5 | +- Put cursor on 'add' below and press F12 - should jump to calculator.py | ||
| 6 | +- Put cursor on 'calculate_total' and press Shift+F12 - find all usages | ||
| 7 | +- Use Ctrl+Shift+T and search for "multiply" - should find it in calculator.py | ||
| 8 | +""" | ||
| 9 | + | ||
| 10 | +from calculator import add, subtract, multiply, calculate_total | ||
| 11 | + | ||
| 12 | + | ||
| 13 | +def process_data(numbers): | ||
| 14 | + """Process a list of numbers using calculator functions.""" | ||
| 15 | + # Test: F12 on 'add' should jump to calculator.py | ||
| 16 | + sum_result = add(numbers[0], numbers[1]) | ||
| 17 | + | ||
| 18 | + # Test: F12 on 'multiply' should jump to calculator.py | ||
| 19 | + product = multiply(sum_result, 2) | ||
| 20 | + | ||
| 21 | + # Test: Shift+F12 on 'calculate_total' should show usages | ||
| 22 | + total = calculate_total(numbers) | ||
| 23 | + | ||
| 24 | + return { | ||
| 25 | + 'sum': sum_result, | ||
| 26 | + 'product': product, | ||
| 27 | + 'total': total | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + | ||
| 31 | +class DataProcessor: | ||
| 32 | + """A class for processing numerical data. | ||
| 33 | + | ||
| 34 | + Test Document Symbols (Ctrl+Shift+O) to see this class structure. | ||
| 35 | + """ | ||
| 36 | + | ||
| 37 | + def __init__(self, data): | ||
| 38 | + self.data = data | ||
| 39 | + self.processed = False | ||
| 40 | + | ||
| 41 | + def calculate_sum(self): | ||
| 42 | + """Calculate sum using calculator module.""" | ||
| 43 | + return calculate_total(self.data) | ||
| 44 | + | ||
| 45 | + def calculate_average(self): | ||
| 46 | + """Calculate average of the data.""" | ||
| 47 | + total = self.calculate_sum() | ||
| 48 | + return divide(total, len(self.data)) # ERROR: 'divide' not imported | ||
| 49 | + | ||
| 50 | + def process(self): | ||
| 51 | + """Process the data.""" | ||
| 52 | + self.processed = True | ||
| 53 | + return self.calculate_average() | ||
| 54 | + | ||
| 55 | + | ||
| 56 | +# Test with intentional error | ||
| 57 | +def main(): | ||
| 58 | + numbers = [1, 2, 3, 4, 5] | ||
| 59 | + | ||
| 60 | + # This works | ||
| 61 | + result = process_data(numbers) | ||
| 62 | + print(f"Results: {result}") | ||
| 63 | + | ||
| 64 | + # This has errors | ||
| 65 | + processor = DataProcessor(numbers) | ||
| 66 | + avg = processor.process() # Will error due to missing 'divide' import | ||
| 67 | + print(f"Average: {avg}") | ||
| 68 | + | ||
| 69 | + | ||
| 70 | +if __name__ == "__main__": | ||
| 71 | + main() | ||
tests/scratch_files/math_utils.f90added@@ -0,0 +1,89 @@ | |||
| 1 | +module math_utils | ||
| 2 | + ! Simple math utilities for testing LSP features | ||
| 3 | + ! | ||
| 4 | + ! Test: | ||
| 5 | + ! - Syntax highlighting (keywords, comments, strings) | ||
| 6 | + ! - Go to Definition (F12 on subroutine calls) | ||
| 7 | + ! - Find References (Shift+F12 on subroutine names) | ||
| 8 | + ! - Document Symbols (Ctrl+Shift+O to see module structure) | ||
| 9 | + ! - Formatting (Shift+Alt+F) | ||
| 10 | + | ||
| 11 | + implicit none | ||
| 12 | + private | ||
| 13 | + | ||
| 14 | + public :: vector_add, vector_dot, vector_magnitude | ||
| 15 | + public :: matrix_multiply | ||
| 16 | + | ||
| 17 | +contains | ||
| 18 | + | ||
| 19 | + subroutine vector_add(a, b, result, n) | ||
| 20 | + ! Add two vectors element-wise | ||
| 21 | + integer, intent(in) :: n | ||
| 22 | + real, intent(in) :: a(n), b(n) | ||
| 23 | + real, intent(out) :: result(n) | ||
| 24 | + integer :: i | ||
| 25 | + | ||
| 26 | + do i = 1, n | ||
| 27 | + result(i) = a(i) + b(i) | ||
| 28 | + end do | ||
| 29 | + end subroutine vector_add | ||
| 30 | + | ||
| 31 | + function vector_dot(a, b, n) result(dot_product) | ||
| 32 | + ! Calculate dot product of two vectors | ||
| 33 | + integer, intent(in) :: n | ||
| 34 | + real, intent(in) :: a(n), b(n) | ||
| 35 | + real :: dot_product | ||
| 36 | + integer :: i | ||
| 37 | + | ||
| 38 | + dot_product = 0.0 | ||
| 39 | + do i = 1, n | ||
| 40 | + dot_product = dot_product + a(i) * b(i) | ||
| 41 | + end do | ||
| 42 | + end function vector_dot | ||
| 43 | + | ||
| 44 | + function vector_magnitude(vec, n) result(magnitude) | ||
| 45 | + ! Calculate magnitude of a vector | ||
| 46 | + integer, intent(in) :: n | ||
| 47 | + real, intent(in) :: vec(n) | ||
| 48 | + real :: magnitude | ||
| 49 | + integer :: i | ||
| 50 | + real :: sum_squares | ||
| 51 | + | ||
| 52 | + sum_squares = 0.0 | ||
| 53 | + do i = 1, n | ||
| 54 | + sum_squares = sum_squares + vec(i)**2 | ||
| 55 | + end do | ||
| 56 | + magnitude = sqrt(sum_squares) | ||
| 57 | + end function vector_magnitude | ||
| 58 | + | ||
| 59 | + subroutine matrix_multiply(A, B, C, m, n, p) | ||
| 60 | + ! Multiply two matrices: C = A * B | ||
| 61 | + ! A is m x n, B is n x p, C is m x p | ||
| 62 | + integer, intent(in) :: m, n, p | ||
| 63 | + real, intent(in) :: A(m, n), B(n, p) | ||
| 64 | + real, intent(out) :: C(m, p) | ||
| 65 | + integer :: i, j, k | ||
| 66 | + | ||
| 67 | + ! Intentional error: missing initialization | ||
| 68 | + do i = 1, m | ||
| 69 | + do j = 1, p | ||
| 70 | + ! ERROR: C(i,j) not initialized before use | ||
| 71 | + do k = 1, n | ||
| 72 | + C(i, j) = C(i, j) + A(i, k) * B(k, j) | ||
| 73 | + end do | ||
| 74 | + end do | ||
| 75 | + end do | ||
| 76 | + end subroutine matrix_multiply | ||
| 77 | + | ||
| 78 | + ! Intentional error function for diagnostics | ||
| 79 | + subroutine broken_routine(x, y) | ||
| 80 | + real, intent(in) :: x | ||
| 81 | + real, intent(out) :: y | ||
| 82 | + real :: temp | ||
| 83 | + | ||
| 84 | + temp = x * 2.0 | ||
| 85 | + ! ERROR: using undefined variable | ||
| 86 | + y = temp + undefined_var | ||
| 87 | + end subroutine broken_routine | ||
| 88 | + | ||
| 89 | +end module math_utils | ||
tests/scratch_files/test_program.f90added@@ -0,0 +1,43 @@ | |||
| 1 | +program test_program | ||
| 2 | + ! Test program using math_utils module | ||
| 3 | + ! | ||
| 4 | + ! Test cross-file navigation: | ||
| 5 | + ! - F12 on 'vector_add' should jump to math_utils.f90 | ||
| 6 | + ! - Shift+F12 on 'vector_dot' should show all usages | ||
| 7 | + ! - Ctrl+Shift+T and search "vector" to find all vector functions | ||
| 8 | + | ||
| 9 | + use math_utils | ||
| 10 | + implicit none | ||
| 11 | + | ||
| 12 | + integer, parameter :: n = 3 | ||
| 13 | + real :: a(n), b(n), result(n) | ||
| 14 | + real :: dot_prod, mag | ||
| 15 | + integer :: i | ||
| 16 | + | ||
| 17 | + ! Initialize vectors | ||
| 18 | + a = [1.0, 2.0, 3.0] | ||
| 19 | + b = [4.0, 5.0, 6.0] | ||
| 20 | + | ||
| 21 | + ! Test vector addition | ||
| 22 | + ! F12 on vector_add should jump to math_utils.f90 | ||
| 23 | + call vector_add(a, b, result, n) | ||
| 24 | + | ||
| 25 | + print *, 'Vector A:', a | ||
| 26 | + print *, 'Vector B:', b | ||
| 27 | + print *, 'A + B :', result | ||
| 28 | + | ||
| 29 | + ! Test dot product | ||
| 30 | + ! F12 on vector_dot should jump to definition | ||
| 31 | + dot_prod = vector_dot(a, b, n) | ||
| 32 | + print *, 'A · B :', dot_prod | ||
| 33 | + | ||
| 34 | + ! Test magnitude | ||
| 35 | + mag = vector_magnitude(a, n) | ||
| 36 | + print *, '|A| :', mag | ||
| 37 | + | ||
| 38 | + ! Intentional error - missing variable declaration | ||
| 39 | + ! ERROR: 'undefined_result' is not declared | ||
| 40 | + undefined_result = dot_prod * 2.0 | ||
| 41 | + print *, 'Result :', undefined_result | ||
| 42 | + | ||
| 43 | +end program test_program | ||
tests/scratch_files/utils.cadded@@ -0,0 +1,76 @@ | |||
| 1 | +/* | ||
| 2 | + * Simple utility functions for testing LSP features | ||
| 3 | + * | ||
| 4 | + * Test: | ||
| 5 | + * - Diagnostics: Intentional errors marked below | ||
| 6 | + * - Go to Definition: F12 on function calls | ||
| 7 | + * - Find References: Shift+F12 on function names | ||
| 8 | + * - Code Actions: Ctrl+. on errors | ||
| 9 | + * - Formatting: Shift+Alt+F | ||
| 10 | + */ | ||
| 11 | + | ||
| 12 | +#include <stdio.h> | ||
| 13 | +#include <stdlib.h> | ||
| 14 | + | ||
| 15 | +// Calculate factorial | ||
| 16 | +int factorial(int n) { | ||
| 17 | + if (n <= 1) { | ||
| 18 | + return 1; | ||
| 19 | + } | ||
| 20 | + return n * factorial(n - 1); | ||
| 21 | +} | ||
| 22 | + | ||
| 23 | +// Calculate fibonacci number | ||
| 24 | +int fibonacci(int n) { | ||
| 25 | + if (n <= 1) { | ||
| 26 | + return n; | ||
| 27 | + } | ||
| 28 | + return fibonacci(n - 1) + fibonacci(n - 2); | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +// Sum array elements | ||
| 32 | +int sum_array(int *arr, int size) { | ||
| 33 | + int total = 0; | ||
| 34 | + for (int i = 0; i < size; i++) { | ||
| 35 | + total += arr[i]; | ||
| 36 | + } | ||
| 37 | + return total; | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +// Find maximum in array | ||
| 41 | +int find_max(int *arr, int size) { | ||
| 42 | + if (size <= 0) { | ||
| 43 | + return 0; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + int max = arr[0]; | ||
| 47 | + for (int i = 1; i < size; i++) { | ||
| 48 | + if (arr[i] > max) { | ||
| 49 | + max = arr[i]; | ||
| 50 | + } | ||
| 51 | + } | ||
| 52 | + return max; | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +// Intentional error function for diagnostics | ||
| 56 | +int broken_function() { | ||
| 57 | + int x = 10; | ||
| 58 | + int y = 20; | ||
| 59 | + | ||
| 60 | + // ERROR: undefined variable | ||
| 61 | + int result = x + y + undefined_var; | ||
| 62 | + | ||
| 63 | + // ERROR: incompatible pointer type | ||
| 64 | + char *str = result; | ||
| 65 | + | ||
| 66 | + printf("Result: %d\n", result); | ||
| 67 | + return result; | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +// Another error - missing return | ||
| 71 | +int missing_return(int x) { | ||
| 72 | + if (x > 0) { | ||
| 73 | + return x * 2; | ||
| 74 | + } | ||
| 75 | + // ERROR: missing return statement for x <= 0 | ||
| 76 | +} | ||