Skip to content
Merged
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
5 changes: 5 additions & 0 deletions lang/cxx/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package cxx

import (
"fmt"
"time"

"github.com/cloudwego/abcoder/lang/uniast"
Expand All @@ -23,6 +24,10 @@ import (

const MaxWaitDuration = 5 * time.Minute

func InstallLanguageServer() (string, error) {
return "", fmt.Errorf("please install clangd-18 manually. See https://releases.llvm.org/ (clangd is in clang-extra)")
}

func GetDefaultLSP() (lang uniast.Language, name string) {
return uniast.Cxx, "clangd-18"
}
Expand Down
81 changes: 52 additions & 29 deletions lang/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/cloudwego/abcoder/lang/register"
"os"
"os/exec"
"path/filepath"
Expand All @@ -33,6 +32,7 @@ import (
"github.com/cloudwego/abcoder/lang/log"
"github.com/cloudwego/abcoder/lang/lsp"
"github.com/cloudwego/abcoder/lang/python"
"github.com/cloudwego/abcoder/lang/register"
"github.com/cloudwego/abcoder/lang/rust"
"github.com/cloudwego/abcoder/lang/uniast"
)
Expand Down Expand Up @@ -138,40 +138,63 @@ func checkRepoPath(repoPath string, language uniast.Language) (openfile string,
}

func checkLSP(language uniast.Language, lspPath string, args ParseOptions) (l uniast.Language, s string, err error) {
switch language {
case uniast.Rust:
l, s = rust.GetDefaultLSP()
case uniast.Cxx:
l, s = cxx.GetDefaultLSP()
case uniast.Python:
l, s = python.GetDefaultLSP()
case uniast.Java:
l, s = java.GetDefaultLSP(args.LspOptions)
case uniast.Golang:
l = uniast.Golang
s = ""
if _, err := exec.LookPath("go"); err != nil {
if _, err := os.Stat(lspPath); os.IsNotExist(err) {
log.Error("Go compiler not found, please make it excutable!\n", lspPath)
return uniast.Unknown, "", err
if lspPath != "" {
// designated LSP
l = language
s = lspPath
} else {
// default LSP
switch language {
case uniast.Rust:
l, s = rust.GetDefaultLSP()
case uniast.Cxx:
l, s = cxx.GetDefaultLSP()
case uniast.Python:
l, s = python.GetDefaultLSP()
case uniast.Java:
l, s = java.GetDefaultLSP(args.LspOptions)
case uniast.Golang:
if _, err := exec.LookPath("go"); err != nil {
if _, err := os.Stat(lspPath); os.IsNotExist(err) {
log.Error("Go compiler not found, please make it excutable!\n", lspPath)
return uniast.Unknown, "", err
}
}
return uniast.Golang, "", nil
default:
return uniast.Unknown, "", fmt.Errorf("unsupported language: %s", language)
}
return
default:
return uniast.Unknown, "", fmt.Errorf("unsupported language: %s", language)
}
// check if lsp excutable
if lspPath != "" {
if _, err := exec.LookPath(lspPath); err != nil {
if _, err := os.Stat(lspPath); os.IsNotExist(err) {
log.Error("Language server %s not found, please make it excutable!\n", lspPath)
return uniast.Unknown, "", err
}

// lsp already installed
if absLspPath, err := exec.LookPath(s); err == nil {
return l, absLspPath, nil
}

// install the lsp.
log.Error("Language server %s not found. Trying to auto install.\n", s)
s, err = installLanguageServer(language)
if err == nil {
if absLspPath, err := exec.LookPath(s); err == nil {
log.Error("Auto installation ok. lspPath=%s.", absLspPath)
return l, absLspPath, nil
}
s = lspPath
}

return
// install failed or broken (lsp not in PATH)
log.Info("Failed to install language server %s: %+w.\n", s, err)
return uniast.Unknown, "", err
}

func installLanguageServer(language uniast.Language) (string, error) {
switch language {
case uniast.Cxx:
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

191-192 可以删,本来准备加 C 的但是 C 的装的比较多,而且可能干扰系统 C 编译器,所以先搁置了。

return cxx.InstallLanguageServer()
case uniast.Python:
return python.InstallLanguageServer()
default:
return "", fmt.Errorf("auto installation not supported for language: %s", language)
}
}

func collectSymbol(ctx context.Context, cli *lsp.LSPClient, repoPath string, opts collect.CollectOption) (repo *uniast.Repository, err error) {
Expand Down
68 changes: 67 additions & 1 deletion lang/python/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,82 @@
package python

import (
"fmt"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"time"

"github.com/cloudwego/abcoder/lang/log"
"github.com/cloudwego/abcoder/lang/uniast"
"github.com/cloudwego/abcoder/lang/utils"
)

const MaxWaitDuration = 5 * time.Second
const lspName = "pylsp"

func CheckPythonVersion() error {
// Check python3 command availability and get version.
output, err := exec.Command("python3", "--version").CombinedOutput()
if err != nil {
return fmt.Errorf("python3 not found: %w. Do you have it installed? Or is it `python` but not aliased?", err)
}

// The regex is corrected to handle a capital 'P' and correctly capture the minor version.
format := `^Python 3\.(\d+)\..*$`
ptn := regexp.MustCompile(format)
matches := ptn.FindStringSubmatch(strings.TrimSpace(string(output)))
if len(matches) < 2 {
return fmt.Errorf("unexpected `python3 --version` output format: %q", output)
}
subver, err := strconv.ParseInt(matches[1], 10, 64)
if err != nil {
return fmt.Errorf("failed to parse python version from `python3 --version` output %q: %w", output, err)
}
if subver < 9 {
return fmt.Errorf("python version 3.%d is not supported; 3.9 or higher is required", subver)
}
return nil
}

func InstallLanguageServer() (string, error) {
if _, err := os.Stat("go.mod"); os.IsNotExist(err) {
log.Error("Auto installation requires working directory to be /path/to/abcoder/")
return "", fmt.Errorf("bad cwd")
}
if err := CheckPythonVersion(); err != nil {
log.Error("python version check failed: %v", err)
return "", err
}
// git submodule init
log.Error("Installing pylsp...")
if err := exec.Command("git", "submodule", "init").Run(); err != nil {
log.Error("git submodule init failed: %v", err)
return "", err
}
// git submodule update
if err := exec.Command("git", "submodule", "update").Run(); err != nil {
log.Error("git submodule update failed: %v", err)
return "", err
}
// python -m pip install -e projectRoot/pylsp
log.Error("Running `python3 -m pip install -e pylsp/` .\nThis might take some time, make sure the network connection is ok.")
if err := exec.Command("python3", "-m", "pip", "install", "-e", "pylsp/").Run(); err != nil {
log.Error("python -m pip install failed: %v", err)
return "", err
}
if err := exec.Command("pylsp", "--version").Run(); err != nil {
log.Error("`pylsp --version` failed: %v", err)
return "", err
}
log.Error("pylsp installed.")
return lspName, nil
}

func GetDefaultLSP() (lang uniast.Language, name string) {
return uniast.Python, "pylsp"
return uniast.Python, lspName
}

func CheckRepo(repo string) (string, time.Duration) {
Expand Down
Loading