Skip to content

Commit f3dbf27

Browse files
committed
improved Go support and Go project initialisation
1 parent 134d515 commit f3dbf27

8 files changed

Lines changed: 177 additions & 54 deletions

File tree

SHOWCASE.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,20 @@ Complete workflow showing editor, AI assistance, and execution in action of the
4646

4747
---
4848

49+
### Go Language Support - Code Editing
50+
Terminal Intelligence now fully supports Go application development. Experience syntax highlighting, robust context-aware agentic fix features, and seamless editing of `.go` files directly in the split-pane interface.
51+
52+
![TI Go Support - Editing](images/ti-supporting-go.png)
53+
54+
---
55+
56+
### Go Language Support - Execution and Testing
57+
Run and test your Go programs seamlessly within TI using the `Ctrl+R` hotkey. The environment automatically manages background tasks like module initialization (`go mod init`/`go mod tidy`) and executes `go run` or `go test` according to the active file.
58+
59+
![TI Go Support - Running](images/ti-supporting-go-b.png)
60+
61+
---
62+
4963
## Key Features Demonstrated
5064

5165
- **Split-Window Layout**: Efficient workspace with editor and AI assistant side-by-side

images/ti-supporting-go-b.png

134 KB
Loading

images/ti-supporting-go.png

156 KB
Loading

internal/agentic/parser.go

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
// FixParser extracts and validates code fixes from AI responses.
1111
// It provides methods to parse markdown-formatted AI responses, identify which code blocks
1212
// represent actual fixes (versus examples or explanations), and validate syntax for different
13-
// file types (bash, shell, powershell, markdown, python).
13+
// file types (bash, shell, powershell, markdown, python, go).
1414
//
1515
// The parser uses heuristics to distinguish fix blocks from explanatory code:
1616
// - Blocks matching the target file type are prioritized
@@ -22,6 +22,7 @@ import (
2222
// - PowerShell: Checks for unmatched quotes, brackets, and try/catch/finally blocks
2323
// - Markdown: Checks for unmatched code block markers
2424
// - Python: Checks for unmatched quotes, brackets, and basic indentation consistency
25+
// - Go: Checks for unmatched brackets and basic go file structure
2526
type FixParser struct {
2627
debug bool // Enable debug logging
2728
}
@@ -59,43 +60,44 @@ func (p *FixParser) logError(format string, args ...interface{}) {
5960
// Returns a slice of CodeBlock structs
6061
func (p *FixParser) ExtractCodeBlocks(response string) []CodeBlock {
6162
p.logDebug("Extracting code blocks from response (length: %d chars)", len(response))
62-
63+
6364
var blocks []CodeBlock
64-
65+
6566
// Regular expression to match markdown code blocks
6667
// Matches: ```optional-language\ncode content\n```
6768
codeBlockRegex := regexp.MustCompile("(?s)```([a-zA-Z0-9_+-]*)\n(.*?)```")
68-
69+
6970
matches := codeBlockRegex.FindAllStringSubmatch(response, -1)
7071
p.logDebug("Found %d potential code blocks", len(matches))
71-
72+
7273
for i, match := range matches {
7374
if len(match) >= 3 {
7475
language := strings.TrimSpace(match[1])
7576
code := match[2]
76-
77+
7778
// Skip empty code blocks
7879
if strings.TrimSpace(code) == "" {
7980
p.logDebug("Skipping empty code block %d", i+1)
8081
continue
8182
}
82-
83+
8384
// Remove trailing newline if present
8485
code = strings.TrimRight(code, "\n")
85-
86+
8687
p.logDebug("Extracted code block %d: language=%s, size=%d bytes", i+1, language, len(code))
87-
88+
8889
blocks = append(blocks, CodeBlock{
8990
Language: language,
9091
Code: code,
9192
IsWhole: false, // Will be determined by IdentifyFixBlocks
9293
})
9394
}
9495
}
95-
96+
9697
p.logDebug("Extracted %d valid code blocks", len(blocks))
9798
return blocks
9899
}
100+
99101
// IdentifyFixBlocks determines which code blocks represent fixes versus explanations
100102
// It analyzes the blocks and their context to distinguish actual code fixes from examples
101103
// or explanatory code snippets. Returns only the blocks that should be applied as fixes.
@@ -107,7 +109,7 @@ func (p *FixParser) ExtractCodeBlocks(response string) []CodeBlock {
107109
// - Blocks with generic/unspecified language may be fixes if they match file content patterns
108110
func (p *FixParser) IdentifyFixBlocks(blocks []CodeBlock, fileType string) []CodeBlock {
109111
p.logDebug("Identifying fix blocks for file type: %s (total blocks: %d)", fileType, len(blocks))
110-
112+
111113
if len(blocks) == 0 {
112114
return []CodeBlock{}
113115
}
@@ -130,12 +132,12 @@ func (p *FixParser) IdentifyFixBlocks(blocks []CodeBlock, fileType string) []Cod
130132
lineCount := countLines(block.Code)
131133
block.IsWhole = lineCount > 3
132134

133-
p.logDebug("Block %d matches file type (language: %s, lines: %d, isWhole: %v)",
135+
p.logDebug("Block %d matches file type (language: %s, lines: %d, isWhole: %v)",
134136
i+1, block.Language, lineCount, block.IsWhole)
135-
137+
136138
fixBlocks = append(fixBlocks, block)
137139
} else {
138-
p.logDebug("Block %d does not match file type (language: %s vs %s)",
140+
p.logDebug("Block %d does not match file type (language: %s vs %s)",
139141
i+1, normalizedLang, normalizedFileType)
140142
}
141143
}
@@ -176,6 +178,8 @@ func normalizeFileType(fileType string) string {
176178
return "markdown"
177179
case "python", "py":
178180
return "python"
181+
case "go":
182+
return "go"
179183
default:
180184
return fileType
181185
}
@@ -195,6 +199,8 @@ func normalizeLanguage(language string) string {
195199
return "markdown"
196200
case "py", "python":
197201
return "python"
202+
case "go", "golang":
203+
return "go"
198204
default:
199205
return language
200206
}
@@ -244,11 +250,11 @@ func countLines(code string) int {
244250

245251
// ValidateFixSyntax performs basic syntax validation on a fix
246252
// Validates that the code is syntactically appropriate for the file type
247-
// Supports: bash, shell, powershell, markdown, python
253+
// Supports: bash, shell, powershell, markdown, python, go
248254
// Returns an error if validation fails, nil if validation passes
249255
func (p *FixParser) ValidateFixSyntax(code string, fileType string) error {
250256
p.logDebug("Validating syntax for file type: %s (code length: %d bytes)", fileType, len(code))
251-
257+
252258
if strings.TrimSpace(code) == "" {
253259
p.logError("Code is empty")
254260
return fmt.Errorf("code cannot be empty")
@@ -269,6 +275,9 @@ func (p *FixParser) ValidateFixSyntax(code string, fileType string) error {
269275
case "python":
270276
p.logDebug("Performing Python syntax validation")
271277
return validatePythonSyntax(code)
278+
case "go":
279+
p.logDebug("Performing Go syntax validation")
280+
return validateGoSyntax(code)
272281
default:
273282
// For unknown file types, perform minimal validation
274283
p.logDebug("Unknown file type, skipping syntax validation")
@@ -279,7 +288,7 @@ func (p *FixParser) ValidateFixSyntax(code string, fileType string) error {
279288
// validateBashSyntax performs basic bash/shell syntax validation
280289
func validateBashSyntax(code string) error {
281290
// Basic checks for common bash syntax errors
282-
291+
283292
// Check for unmatched quotes
284293
if err := checkUnmatchedQuotes(code); err != nil {
285294
return fmt.Errorf("bash syntax error: %w", err)
@@ -301,7 +310,7 @@ func validateBashSyntax(code string) error {
301310
// validatePowerShellSyntax performs basic PowerShell syntax validation
302311
func validatePowerShellSyntax(code string) error {
303312
// Basic checks for common PowerShell syntax errors
304-
313+
305314
// Check for unmatched quotes
306315
if err := checkUnmatchedQuotes(code); err != nil {
307316
return fmt.Errorf("powershell syntax error: %w", err)
@@ -323,7 +332,7 @@ func validatePowerShellSyntax(code string) error {
323332
// validateMarkdownSyntax performs basic markdown syntax validation
324333
func validateMarkdownSyntax(code string) error {
325334
// Basic checks for markdown syntax
326-
335+
327336
// Check for unmatched code block markers
328337
backtickCount := strings.Count(code, "```")
329338
if backtickCount%2 != 0 {
@@ -394,17 +403,17 @@ func checkUnmatchedBrackets(code string) error {
394403
}
395404

396405
lines := strings.Split(code, "\n")
397-
406+
398407
for _, line := range lines {
399408
trimmed := strings.TrimSpace(line)
400-
409+
401410
// Check if we're in a case statement pattern (ends with ')')
402411
// Case patterns look like: pattern) command;;
403412
if strings.Contains(trimmed, ";;") {
404413
// This line likely contains case patterns, skip bracket checking for ')' in patterns
405414
inCasePattern = true
406415
}
407-
416+
408417
for _, ch := range line {
409418
// Skip characters inside quotes
410419
if escaped {
@@ -446,7 +455,7 @@ func checkUnmatchedBrackets(code string) error {
446455
}
447456
continue
448457
}
449-
458+
450459
if len(stack) == 0 {
451460
return fmt.Errorf("unmatched closing bracket: %c", ch)
452461
}
@@ -460,7 +469,7 @@ func checkUnmatchedBrackets(code string) error {
460469
}
461470
}
462471
}
463-
472+
464473
// Reset case pattern flag at end of line
465474
inCasePattern = false
466475
}
@@ -476,7 +485,7 @@ func checkUnmatchedBrackets(code string) error {
476485
func checkBashControlStructures(code string) error {
477486
// Count control structure keywords
478487
lines := strings.Split(code, "\n")
479-
488+
480489
ifCount := 0
481490
fiCount := 0
482491
doCount := 0
@@ -486,7 +495,7 @@ func checkBashControlStructures(code string) error {
486495

487496
for _, line := range lines {
488497
trimmed := strings.TrimSpace(line)
489-
498+
490499
// Skip comments
491500
if strings.HasPrefix(trimmed, "#") {
492501
continue
@@ -533,16 +542,16 @@ func checkBashControlStructures(code string) error {
533542
func checkPowerShellControlStructures(code string) error {
534543
// PowerShell uses braces for control structures, which are already checked
535544
// by checkUnmatchedBrackets. We can add more specific checks here if needed.
536-
545+
537546
// For now, we'll just ensure basic structure
538547
// PowerShell is case-insensitive, so we normalize to lowercase
539548
lowerCode := strings.ToLower(code)
540-
549+
541550
// Check for incomplete try/catch/finally blocks
542551
tryCount := strings.Count(lowerCode, "try")
543552
catchCount := strings.Count(lowerCode, "catch")
544553
finallyCount := strings.Count(lowerCode, "finally")
545-
554+
546555
// Try blocks should have at least one catch or finally
547556
if tryCount > 0 && (catchCount+finallyCount) == 0 {
548557
return fmt.Errorf("try block without catch or finally")
@@ -554,7 +563,7 @@ func checkPowerShellControlStructures(code string) error {
554563
// validatePythonSyntax performs basic Python syntax validation
555564
func validatePythonSyntax(code string) error {
556565
// Basic checks for common Python syntax errors
557-
566+
558567
// Check for unmatched quotes
559568
if err := checkUnmatchedQuotes(code); err != nil {
560569
return fmt.Errorf("python syntax error: %w", err)
@@ -576,39 +585,54 @@ func validatePythonSyntax(code string) error {
576585
// checkPythonIndentation performs basic Python indentation validation
577586
func checkPythonIndentation(code string) error {
578587
lines := strings.Split(code, "\n")
579-
588+
580589
// Track if we're expecting an indented block
581590
expectIndent := false
582591
prevIndent := 0
583-
592+
584593
for i, line := range lines {
585594
trimmed := strings.TrimSpace(line)
586-
595+
587596
// Skip empty lines and comments
588597
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
589598
continue
590599
}
591-
600+
592601
// Calculate indentation level
593602
indent := len(line) - len(strings.TrimLeft(line, " \t"))
594-
603+
595604
// Check if line ends with colon (starts a block)
596605
if strings.HasSuffix(trimmed, ":") {
597606
expectIndent = true
598607
prevIndent = indent
599608
continue
600609
}
601-
610+
602611
// If we expected indentation, check that it increased
603612
if expectIndent {
604613
if indent <= prevIndent {
605614
return fmt.Errorf("expected indented block after line %d", i)
606615
}
607616
expectIndent = false
608617
}
609-
618+
610619
prevIndent = indent
611620
}
612-
621+
622+
return nil
623+
}
624+
625+
// validateGoSyntax performs basic Go syntax validation
626+
func validateGoSyntax(code string) error {
627+
// Check for unmatched quotes
628+
if err := checkUnmatchedQuotes(code); err != nil {
629+
return fmt.Errorf("go syntax error: %w", err)
630+
}
631+
632+
// Check for unmatched brackets/parentheses
633+
if err := checkUnmatchedBrackets(code); err != nil {
634+
return fmt.Errorf("go syntax error: %w", err)
635+
}
636+
613637
return nil
614638
}

0 commit comments

Comments
 (0)