Files
wehub-resource-sync a06f331eb8
install-script / powershell-syntax (push) Waiting to run
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
install-script / install (macos-14) (push) Waiting to run
install-script / install (ubuntu-latest) (push) Waiting to run
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

150 lines
4.3 KiB
Go

package serverstack
import (
"os"
"path/filepath"
"strings"
"go.uber.org/zap"
"github.com/zzet/gortex/internal/config"
"github.com/zzet/gortex/internal/resolver"
"github.com/zzet/gortex/internal/semantic/lsp"
)
// IsFalsyEnv reports whether the named env var holds a falsy value
// (0/false/no/off/n, case-insensitive). Empty/unset is NOT falsy.
func IsFalsyEnv(name string) bool {
switch strings.ToLower(strings.TrimSpace(os.Getenv(name))) {
case "0", "false", "no", "off", "n":
return true
default:
return false
}
}
// LspDisabledSet builds the set of LSP spec names that should NOT be
// auto-registered by Router.RegisterAvailable, merging per-spec config
// opt-outs (semantic.providers with enabled:false that resolve to a
// known LSP spec) with the comma-separated GORTEX_LSP_DISABLE env var.
// The special key "__all__" (from the literal "all"/"*") signals
// "skip auto-register everywhere" and is checked separately by callers.
func LspDisabledSet(providers []config.SemanticProviderConfig, envVar string) map[string]bool {
out := map[string]bool{}
for _, pc := range providers {
if pc.Enabled {
continue
}
if lsp.SpecByName(pc.Name) != nil {
out[pc.Name] = true
}
}
for _, raw := range strings.Split(envVar, ",") {
name := strings.TrimSpace(raw)
if name == "" {
continue
}
if strings.EqualFold(name, "all") || name == "*" {
out["__all__"] = true
continue
}
out[name] = true
}
return out
}
// RepoLikelyHasTypeScriptIntent reports whether a repo root carries one
// of the canonical TS/JS project markers, used to decide whether to wire
// the resolve-time tsserver helper for a tracked repo.
func RepoLikelyHasTypeScriptIntent(absRoot string) bool {
for _, marker := range []string{"tsconfig.json", "jsconfig.json", "package.json"} {
if _, err := os.Stat(filepath.Join(absRoot, marker)); err == nil {
return true
}
}
return false
}
// RepoLikelyHasPythonIntent reports whether a repo root carries one of the
// standard Python project markers, used to decide whether to wire the
// resolve-time pyright helper for a tracked repo.
func RepoLikelyHasPythonIntent(absRoot string) bool {
for _, marker := range []string{
"pyproject.toml",
"setup.py",
"setup.cfg",
"requirements.txt",
"requirements.in",
"Pipfile",
"poetry.lock",
"uv.lock",
"tox.ini",
".python-version",
} {
if _, err := os.Stat(filepath.Join(absRoot, marker)); err == nil {
return true
}
}
if matches, err := filepath.Glob(filepath.Join(absRoot, "*.py")); err == nil && len(matches) > 0 {
return true
}
return false
}
// BuildResolverLSPHelper constructs the resolve-time LSP helper for a
// workspace, choosing the router-cached lazy path (poolSize <= 1, reuses
// the router's idle reaper) or the fresh-spawn pool path (poolSize > 1,
// opt-in via GORTEX_LSP_POOL_SIZE; keeps every spawn alive, so only for
// small tracked-workspace counts).
func BuildResolverLSPHelper(router *lsp.Router, spec *lsp.ServerSpec, absRoot string, poolSize int, logger *zap.Logger) *lsp.ResolverHelper {
if poolSize <= 1 {
return lsp.NewLazyResolverHelper(
func() (*lsp.Provider, error) {
return router.ForSpecWorkspace(spec, absRoot)
},
absRoot,
spec.Extensions,
0,
logger,
)
}
return lsp.NewPooledResolverHelper(
func() (*lsp.Provider, error) {
return lsp.SpawnProviderForResolver(spec, absRoot, logger)
},
absRoot,
spec.Extensions,
0,
poolSize,
logger,
)
}
// BuildResolverLSPHelperForRepo constructs a per-repo helper that can route
// each file extension to the appropriate language server. The returned spec
// names are the helpers included in the mux, for logging and diagnostics.
func BuildResolverLSPHelperForRepo(router *lsp.Router, absRoot string, poolSize int, logger *zap.Logger) (resolver.LSPHelper, []string) {
if router == nil {
return nil, nil
}
var helpers []resolver.LSPHelper
var specs []string
add := func(name string, enabled bool) {
if !enabled {
return
}
spec := lsp.SpecByName(name)
if spec == nil || !router.Available(spec) {
return
}
helpers = append(helpers, BuildResolverLSPHelper(router, spec, absRoot, poolSize, logger))
specs = append(specs, name)
}
add("typescript-language-server", RepoLikelyHasTypeScriptIntent(absRoot))
add("pyright", RepoLikelyHasPythonIntent(absRoot))
return lsp.NewResolverHelperMux(helpers...), specs
}