lsp-bridge -- 速度最快的语法补全插件

有人在折腾tailwindcss server的吗?我正在尝试为lsp-bridge添加tailwind server的支持。

折腾思路:

  1. 研究lsp-mode下tailwind client的参数有哪些 根据我的提取,得到以下参数配置:
{
"name": "tailwindcss",
"languageId": "html",
"command": ["tailwindcss-language-server", "--stdio"],
"settings": {},
"capabilities": {},
"initializationOptions": {
  "configuration": {
    "tailwindCSS": {
      "emmetCompletions": false,
      "showPixelEquivalents": true,
      "rootFontSize": 16,
      "validate": true,
      "lint": {
        "invalidScreen": "error",
        "invalidVariant": "error",
        "invalidTailwindDirective": "error",
        "invalidApply": "error",
        "invalidConfigPath": "error",
        "cssConflict": "warning",
        "recommendedVariantOrder": "warning"
      },
      "experimental": {
        "classRegex": "",
        "configFile": "tailwind.config.js"
      },
      "classAttributes": ["class", "className", "ngClass"]
    }
  }
}
}

但是通过以上参数初始化服务器会得到如下结果:

--- Send (63379): initialize
{
   "id": 63379,
   "method": "initialize",
   "params": {
      "processId": 3254507,
      "rootPath": "/home/evanmeek/Documents/code/project/web/domeland-ui",
      "clientInfo": {
         "name": "emacs",
         "version": "GNU Emacs 28.1 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.33, cairo version 1.17.6)\n of 2022-04-28"
      },
      "rootUri": "file:///home/evanmeek/Documents/code/project/web/domeland-ui",
      "capabilities": {},
      "initializationOptions": {
         "configuration": {
            "tailwindCSS": {
               "emmetCompletions": false,
               "showPixelEquivalents": true,
               "rootFontSize": 16,
               "validate": true,
               "lint": {
                  "invalidScreen": "error",
                  "invalidVariant": "error",
                  "invalidTailwindDirective": "error",
                  "invalidApply": "error",
                  "invalidConfigPath": "error",
                  "cssConflict": "warning",
                  "recommendedVariantOrder": "warning"
               },
               "experimental": {
                  "classRegex": "",
                  "configFile": "tailwind.config.js"
               },
               "classAttributes": [
                  "class",
                  "className",
                  "ngClass"
               ]
            }
         }
      }
   },
   "jsonrpc": "2.0"
}

--- Recv message (error):
{
   "jsonrpc": "2.0",
   "id": 63379,
   "error": {
      "code": -32603,
      "message": "Request initialize failed with message: Cannot read properties of undefined (reading 'hover')"
   }
}

随后我通过阅读tailwind-server的源码进行了修改,但是目前不知道如何debug tailwindserver(如何看它的输出日志)。

有大佬知道的请@我,十分感谢!

有了tailwindcss server的日志我就可以更好的debug,否则瞎猜参数不知道得撞墙到猴年马月呀

看样子少传了一个 hover 属性呀。

是的,但是我补上后还是会有其他问题

所有就想着能不能debug到server的日志,这样就能仔细排查了

你用 ripgrep 去搜索源代码呢? 就用 Request initialize failed with message , 这样你可以看看服务器到底想要的是哪个key你没有?

rg搜索过,没有找到有关的字符串,看来可能是lsp自动处理的

但是我已经定位到初始化的那个函数了

我给配置加上这段:

"capabilities": {
         "textDocument": {
            "hover": {
               "dynamicRegistration": true
            }
         }
      },

可以做到不提示hover错误,但是会提示 “message”: “Request initialize failed with message: Cannot read properties of undefined (reading ‘dynamicRegistration’)”

可根据lsp协议文档,我已经设定了这个 dnyamicRegistration

尝试把textDocument/hover/dynamicRegistration设置为false解决了上面的问题

下面开始提示这个错误了:

--- Recv notification: window/logMessage
{
   "jsonrpc": "2.0",
   "method": "window/logMessage",
   "params": {
      "type": 1,
      "message": "Unhandled exception: Cannot read properties of undefined (reading 'files')\nTypeError: Cannot read properties of undefined (reading 'files')\n    at /usr/bin/tailwindcss-language-server:690:1862\n    at Generator.next (<anonymous>)\n    at i (/usr/bin/tailwindcss-language-server:2:1059)"
   }
}

从错误中可以看出直接给了代码出错的行数,可惜这个代码是被压缩过的.

不过我看了源码,可能还需要处理onCompletetion的错误,这个错误可能就是onCompletion出现的错误了

async init(): Promise<void> {
    if (this.initialized) return;

    this.initialized = true;

    // TODO
    let workspaceFolders: Array<ProjectConfig> =
      false &&
      Array.isArray(this.initializeParams.workspaceFolders) &&
      this.initializeParams.capabilities.workspace?.workspaceFolders
        ? this.initializeParams.workspaceFolders.map((el) => ({
            folder: getFileFsPath(el.uri),
          }))
        : this.initializeParams.rootPath
        ? [
            {
              folder: normalizeFileNameToFsPath(this.initializeParams.rootPath),
            },
          ]
        : [];

    if (workspaceFolders.length === 0) {
      console.error("No workspace folders found, not initializing.");
      return;
    }

    let configFileOrFiles = dlv(
      await connection.workspace.getConfiguration("tailwindCSS"),
      "experimental.configFile",
      null
    ) as Settings["tailwindCSS"]["experimental"]["configFile"];

    if (configFileOrFiles) {
      let base = workspaceFolders[0].folder;

      if (
        typeof configFileOrFiles !== "string" &&
        (!isObject(configFileOrFiles) ||
          !Object.entries(configFileOrFiles).every(([key, value]) => {
            if (typeof key !== "string") return false;
            if (Array.isArray(value)) {
              return value.every((item) => typeof item === "string");
            }
            return typeof value === "string";
          }))
      ) {
        console.error(
          "Invalid `experimental.configFile` configuration, not initializing."
        );
        return;
      }

      let configFiles =
        typeof configFileOrFiles === "string"
          ? { [configFileOrFiles]: "**" }
          : configFileOrFiles;

      workspaceFolders = Object.entries(configFiles).map(
        ([relativeConfigPath, relativeDocumentSelectorOrSelectors]) => {
          return {
            folder: base,
            configPath: path.join(base, relativeConfigPath),
            documentSelector: []
              .concat(relativeDocumentSelectorOrSelectors)
              .map((selector) => path.join(base, selector)),
          };
        }
      );
    }

    await Promise.all(
      workspaceFolders.map((projectConfig) =>
        this.addProject(projectConfig, this.initializeParams)
      )
    );

    this.setupLSPHandlers();

    if (
      this.initializeParams.capabilities.workspace?.didChangeWatchedFiles
        ?.dynamicRegistration
    ) {
      this.connection.onDidChangeWatchedFiles(({ changes }) => {
        for (let [, project] of this.projects) {
          project.onFileEvents(
            changes.map(({ uri, type }) => ({
              file: URI.parse(uri).fsPath,
              type,
            }))
          );
        }
      });
    }

    this.connection.onDidChangeConfiguration(async ({ settings }) => {
      for (let [, project] of this.projects) {
        project.onUpdateSettings(settings);
      }
    });

    this.connection.onShutdown(() => {
      this.dispose();
    });

    this.documentService.onDidChangeContent((change) => {
      this.getProject(change.document)?.provideDiagnostics(change.document);
    });
  }
```typescript
private setupLSPHandlers() {
    this.connection.onHover(this.onHover.bind(this));
    this.connection.onCompletion(this.onCompletion.bind(this));
    this.connection.onCompletionResolve(this.onCompletionResolve.bind(this));
    this.connection.onDocumentColor(this.onDocumentColor.bind(this));
    this.connection.onColorPresentation(this.onColorPresentation.bind(this));
    this.connection.onCodeAction(this.onCodeAction.bind(this));
  }

这个问题调了很久都没找到解决方法,但是我发现一个调试方法,只需要在源码内加上console.log(msg) 这个server会自动把log的信息以window/logMessage的形式返回,这样我就有一个简单的调试工具了

错误定位到addProject这一步了!果然还是log大法好

1 个赞

为什么查引用这里使用lsp-bridge-find-def ?

这是 bug 还是 feature

@zwPapEr 帮忙看看?

这个问题已经被 Add support textEdit by jadestrong · Pull Request #113 · manateelazycat/lsp-bridge · GitHub 修复了,你更新到最新版了吗?

eglot 能够处理这种情况吗? 如果可以,能否帮忙对比一下 eglot 和 lsp-bridge 的日志? 谢谢

更新了,看样子不是同一个问题,和现在 issue 里提的估计是同一个,主要是偶现,频率非常低,我写一天代码也就出现那么几次,等上班把 issue 里提到的那几个地方打上日志看下

好的,有日志就好修复,感谢反馈

本来今天想试一下pylance, 配置都加好了

{
  "name": "pylance",
  "languageId": "python",
  "command": ["pylance-language-server", "--stdio"],
  "settings": {
    "python.analysis.typeCheckingMode": "basic",
    "python.analysis.diagnosticMode": "openFilesOnly",
    "python.analysis.stubPath": "./typings",
    "python.analysis.autoSearchPaths": true,
    "python.analysis.extraPaths": [],
    "python.analysis.diagnosticSeverityOverrides": {},
    "python.analysis.useLibraryCodeForTypes": true,
    "python.analysis.autoImportCompletions": true,
    "python.analysis.completeFunctionParens": false
  }
}

pylance一启动就不让我们用呀:

You may install and use any number of copies of the software only with Microsoft Visual Studio, 
Visual Studio for Mac, Visual Studio Code, Azure DevOps, Team Foundation Server, and successor 
Microsoft products and services (collectively, the “Visual Studio Products and Services”) to develop and
 test your applications. The software is licensed, not sold. This agreement only gives you some rights to 
use the software. Microsoft reserves all other rights. You may not: work around any technical limitations in 
the software that only allow you to use it in certain ways; reverse engineer, decompile or disassemble the
 software, or otherwise attempt to derive the source code for the software, except and to the extent 
required by third party licensing terms governing use of certain open source components that may be 
included in the software; remove, minimize, block, or modify any notices of Microsoft or its suppliers in the 
software; use the software in any way that is against the law or to create or propagate malware; or share, 
publish, distribute, or lease the software (except for any distributable code, subject to the terms above), 
provide the software as a stand-alone offering for others to use, or transfer the software or this agreement 
to any third party.
1 个赞

大佬,elgot是正常的。 这个是eglot的操作,一样的操作下,lsp-bridge 和 eglot的日志附后; simplescreenrecorder-2022-05-21_11.47.06

lsp-bridge

eglot

非常感谢。

我推送了一个补丁

更新后尝试一下。

有可能是这个补丁的锅,我看看。

1 个赞

应该和 pyright.json 里面配置 stubPath 也有关系,我尝试 pyright --createstub scipy 并修改 stubPath 以后,还是不行的。

等以后看看其他人研究了。