Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions _extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
],
"default": "verbose",
"description": "Trace TypeScript Go server communication."
},
"typescript-go.memoryLimit": {
"type": "string",
"default": "",
"description": "Memory limit for the TypeScript Go language server (e.g., '2GiB', '500MiB'). Leave empty for no limit.",
"pattern": "^([0-9]+(\\.[0-9]+)?([KMGT]i)?B)?$",
"patternErrorMessage": "Must be a valid memory size (e.g., '2GiB', '500MiB', '1024B')"
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions _extension/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ export function activate(context: vscode.ExtensionContext) {
},
};

const config = vscode.workspace.getConfiguration("typescript-go");
const memoryLimit = config.get<string>("memoryLimit");

const clientOptions: LanguageClientOptions = {
documentSelector: [
{ scheme: "file", language: "typescript" },
Expand All @@ -52,6 +55,7 @@ export function activate(context: vscode.ExtensionContext) {
],
outputChannel: output,
traceOutputChannel: traceOutput,
...(memoryLimit ? { initializationOptions: { memoryLimit: memoryLimit } } : {}),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't need to be an init option for the LS, you can just set GOMEMLIMIT as an env var for the process

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakebailey do you mean for VSCode itself? because that's how I was testing this, like

GOMEMLIMIT=2048MiB code .

but then obviously that sets it for anything you run within the integrated VSCode terminal etc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

diagnosticPullOptions: {
onChange: true,
onSave: true,
Expand Down
50 changes: 50 additions & 0 deletions internal/lsp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"errors"
"fmt"
"io"
"runtime/debug"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -211,6 +213,21 @@ func (s *Server) handleMessage(req *lsproto.RequestMessage) error {

func (s *Server) handleInitialize(req *lsproto.RequestMessage) error {
s.initializeParams = req.Params.(*lsproto.InitializeParams)

// Handle memory limit from initialization options
if s.initializeParams.InitializationOptions != nil {
if opts, ok := (*s.initializeParams.InitializationOptions).(map[string]any); ok {
if memLimitStr, ok := opts["memoryLimit"].(string); ok && memLimitStr != "" {
if limit, err := parseMemoryLimit(memLimitStr); err != nil {
s.Log("Failed to parse memory limit:", err)
} else {
debug.SetMemoryLimit(limit)
s.Log(fmt.Sprintf("Set memory limit to %s (%d bytes)", memLimitStr, limit))
}
}
}
}

return s.sendResult(req.ID, &lsproto.InitializeResult{
ServerInfo: &lsproto.ServerInfo{
Name: "typescript-go",
Expand Down Expand Up @@ -397,3 +414,36 @@ func codeFence(lang string, code string) string {
}
return result.String()
}

// parseMemoryLimit parses a memory limit string (e.g., "2GiB", "500MiB") into bytes.
// Supports: B, KiB, MiB, GiB, TiB (IEC binary prefixes).
func parseMemoryLimit(s string) (int64, error) {
if s == "" {
return -1, fmt.Errorf("empty memory limit")
}

multipliers := map[string]int64{
"B": 1,
"KiB": 1024,
"MiB": 1024 * 1024,
"GiB": 1024 * 1024 * 1024,
"TiB": 1024 * 1024 * 1024 * 1024,
}

// Try each suffix
for suffix, multiplier := range multipliers {
if strings.HasSuffix(s, suffix) {
numStr := strings.TrimSuffix(s, suffix)
num, err := strconv.ParseFloat(numStr, 64)
if err != nil {
return -1, fmt.Errorf("invalid number in memory limit %q: %w", s, err)
}
if num <= 0 {
return -1, fmt.Errorf("memory limit must be positive: %q", s)
}
return int64(num * float64(multiplier)), nil
}
}

return -1, fmt.Errorf("invalid memory limit format %q (expected suffix: B, KiB, MiB, GiB, or TiB)", s)
}