ROCKTAKEY / lsp-latex

Emacs lsp-mode client for LaTeX, on texlab.
GNU General Public License v3.0
69 stars 4 forks source link

Company, texlab, lsp-mode, and lsp-latex based completion, as well as the corresponding configuration with company, texlab, and eglot. #29

Closed hongyi-zhao closed 2 years ago

hongyi-zhao commented 3 years ago

On Ubuntu 20.04, according to the instruction here, I try to configure and test lsp-latex with the following steps:

  1. Install texlab.

Retrieve the released package from here, then do the following:

$ tar -zxvf texlab-x86_64-linux.tar.gz
$ mv texlab ~/.local/bin
  1. Install and configure lsp-mode and lsp-latex through straight.
(use-package lsp-mode)
(require 'lsp-mode)

(use-package lsp-latex
  :straight (:host github :repo "ROCKTAKEY/lsp-latex"))

(require 'lsp-latex)
;; "texlab" must be located at a directory contained in `exec-path'.
;; If you want to put "texlab" somewhere else,
;; you can specify the path to "texlab" as follows:
;; (setq lsp-latex-texlab-executable "/path/to/texlab")

(with-eval-after-load "tex-mode"
 (add-hook 'tex-mode-hook 'lsp)
 (add-hook 'latex-mode-hook 'lsp))

;; For YaTeX
(with-eval-after-load "yatex"
 (add-hook 'yatex-mode-hook 'lsp))

;; For bibtex
(with-eval-after-load "bibtex"
 (add-hook 'bibtex-mode-hook 'lsp))

Now, I open some TeX document and still can't have the lsp-latex enabled. Any hints for this problem?

Regards, HY

ROCKTAKEY commented 3 years ago

First, is there any message from LSP-mode? such as:

LSP :: texlab2:9999 initialized successfully in folders: (/path/to/folder)

The message can be seen in *Message* buffer. Searching with command C-s LSP and C-s texlab in the *Message* buffer is helpful. If you find similar lines (including the lines which don't imply successful initialization), please paste the lines here.

hongyi-zhao commented 3 years ago

Searching with command C-s LSP and C-s texlab in the Message buffer is helpful.

I tried it and found nothing.

image

ROCKTAKEY commented 3 years ago

Sorry, I lacked some words. Please do same after opening tex file.

hongyi-zhao commented 3 years ago

I use the following minimal init file, ~/.emacs.d/init.lsp-latex, to do the test:

;$ emacs -q --load ~/.emacs.d/init.lsp-latex
;;Bootstrap straight
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))
(straight-use-package 'use-package)
(setq straight-use-package-by-default t)

(use-package lsp-mode)
(require 'lsp-mode)

(use-package lsp-latex
  :straight (:host github :repo "ROCKTAKEY/lsp-latex"))

(require 'lsp-latex)
;; "texlab" must be located at a directory contained in `exec-path'.
;; If you want to put "texlab" somewhere else,
;; you can specify the path to "texlab" as follows:
;; (setq lsp-latex-texlab-executable "/path/to/texlab")

(with-eval-after-load "tex-mode"
 (add-hook 'tex-mode-hook 'lsp)
 (add-hook 'latex-mode-hook 'lsp))

And see the following in the lsp-log buffer:

image

ROCKTAKEY commented 3 years ago

Thanks. Texlab executable seems to be found, and lsp-latex client seems to be loaded properly. Do you use other lsp server? If so, completion works well? When it is your first time to use lsp-mode, or completion does not work well on other lsp clitents, you should additionally install company (for auto completion), or just use C-M-i (completion-at-point; for self completion) after the point you want to complete.

hongyi-zhao commented 3 years ago

I added the company relative code as below:

(use-package company)
(add-hook 'after-init-hook 'global-company-mode)

But I still can't have an incremental drop-down candidate menu triggered at the point, and when I run M-x lsp-mode RET, I will meet the following error:

image

But I can work with auctex, eglot, texlab, and company smoothly, as described here.

Regards, HY

ROCKTAKEY commented 3 years ago

I'm afraid but I cannot find obvious problem. So next, please eval (setq lsp-log-io t), and open tex file. Then the buffers named like "texlab2", "texlab2::stderr", and "lsp-log: texlab2:9999" are created, so please paste contents of them. In addition, I'd like to see messages from lsp-mode in Message buffer after opening tex fie.

hongyi-zhao commented 3 years ago

Based on your above instructions, I use the following testing code to start Emacs:

(use-package company)
(add-hook 'after-init-hook 'global-company-mode)

(use-package lsp-mode)
(require 'lsp-mode)

(use-package lsp-latex
  :straight (:host github :repo "ROCKTAKEY/lsp-latex"))

(require 'lsp-latex)
;; "texlab" must be located at a directory contained in `exec-path'.
;; If you want to put "texlab" somewhere else,
;; you can specify the path to "texlab" as follows:
;; (setq lsp-latex-texlab-executable "/path/to/texlab")

(with-eval-after-load "latex-mode"
 (add-hook 'latex-mode-hook 'lsp))

(setq lsp-log-io t)

Then I open a tex file. But I don't have any buffers named like "texlab2", "texlab2::stderr", and "lsp-log: texlab2:9999", as shown below:

image

There are no messages from lsp-mode in Message buffer after opening tex fie.

ROCKTAKEY commented 3 years ago

Umm. Can I have your *Message* buffer after opening tex file? LSP-mode should send some message when it disconnects texlab server.

hongyi-zhao commented 3 years ago

See below:

image

NB. Considering that I'm using auctex, the following adjustment has been adopted:

(with-eval-after-load "latex-mode"
 ;If you are using AUCTeX you might need to use TeX-mode-hook instead:
 (add-hook 'TeX-mode-hook 'lsp))
ROCKTAKEY commented 3 years ago

It is strange. The command lsp send message whenever it is called. lsp might not be called. Could you run M-x lsp in tex file, to ensure lsp run?

hongyi-zhao commented 3 years ago

M-x lsp RET:

image image

ROCKTAKEY commented 3 years ago

Thanks. First image suggests that the tex file is in the blacklisted dir, or the tex file is not in project.

  1. Ensure that the tex file is not in blacklist. You can get blacklist by pasting (insert (pp (lsp-session-folders-blacklist (lsp-session)))) in *scratch* buffer and running C-x C-e with point after it.
  2. Ensure that the tex file is in project. In the tex file, push M-:, paste below code and send RET. When "Not in the project" is messaged, the file is not in the project. please put the file to project, such as dir managed by git.
    (if (lsp--calculate-root (lsp-session) (buffer-file-name))
    (message "In the project")
    (message "Not in the project"))

NB. Considering that I'm using auctex, the following adjustment has been adopted:

Feature "latex-mode" is not exist, so using "tex-site" is better. Or, actually, with-eval-after-load is not needed. So with AUCTeX, just write below:

(with-eval-after-load "tex-site"
 (add-hook 'TeX-mode-hook 'lsp))
;or
 (add-hook 'TeX-mode-hook 'lsp)

I will add instruction for AUCTeX later. Thanks.

hongyi-zhao commented 3 years ago

Ensure that the tex file is not in blacklist. You can get blacklist by pasting (insert (pp (lsp-session-folders-blacklist (lsp-session)))) in scratch buffer and running C-x C-e with point after it.

image

Now, I installed the projectile package as follows:

;https://github.com/bbatsov/projectile
(use-package projectile)
(projectile-mode +1)
;; Recommended keymap prefix on macOS
(define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
;; Recommended keymap prefix on Windows/Linux
(define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)

And then do the following:

$ mkdir test && cd $_
$ mv ../test.tex .
$ git init .

Then I open the above test.tex file from Emacs and do the following testing:

(if (lsp--calculate-root (lsp-session) (buffer-file-name))
   (message "In the project")
 (message "Not in the project"))

See below for the result:

image

ROCKTAKEY commented 3 years ago

Good. Now you should be able to use lsp-mode. Could you reopen the tex file? The message like the image will appear (if not, run M-x lsp). Then, type i to select the project root "/home/werner/test/". Then, your Emacs will connect texlab2 server, and you will be able to use all feature such as completion. (If you want to use auto completion, use company as I said).

hongyi-zhao commented 3 years ago

The currently used configurations is shown below:

(use-package company)
(setq company-idle-delay 0) 
(setq company-minimum-prefix-length 1)
(add-hook 'after-init-hook 'global-company-mode)

(use-package lsp-mode)
(require 'lsp-mode)

(use-package lsp-latex
  :straight (:host github :repo "ROCKTAKEY/lsp-latex"))

(require 'lsp-latex)
;; "texlab" must be located at a directory contained in `exec-path'.
;; If you want to put "texlab" somewhere else,
;; you can specify the path to "texlab" as follows:
;; (setq lsp-latex-texlab-executable "/path/to/texlab")

;https://github.com/ROCKTAKEY/lsp-latex/issues/29#issuecomment-865711274
(add-hook 'TeX-mode-hook 'lsp)

(setq lsp-log-io t)

But with the above settings, I still must manually run M-x company-mode RET after I open a tex document to have the completion function.

Could you reopen the tex file?

Why must I reopen the file? Based on my tries, without the use of the projectile package, once I open a tex document from any location, I'll see the following:

image

image

you will be able to use all feature such as completion. (If you want to use auto completion, use company as I said).

But I can only have partial LaTeX command completion, as shown below:

image

The \href command can't be completed:

image

If I hit C-M-i, the following info will be shown:

image

But with auctex, eglot, texlab, and company, all the commands will be listed:

image

ROCKTAKEY commented 3 years ago

But with the above settings, I still must manually run M-x company-mode RET after I open a tex document to have the completion function.

Put (global-company-mode +1) to your init.el if you want to use company on all buffer, or put (add-hook 'TeX-mode-hook #'company-mode) for use on tex buffer.

Why must I reopen the file? Based on my tries, without the use of the projectile package, once I open a tex document from any location, I'll see the following:

It is just for confirmation that opening tex file leads to lsp. If you re-run emacs, re-opening is not needed.

But I can only have partial LaTeX command completion, as shown below:

Texlab server seems not to be connected to Emacs, yet. When you open tex file first, you get message like below (as you've gotten on the test) if texlab is connected. Type i or I for select project. The project is saved for next time. image

After selecting project root, or from the second time onwards, you get the message like below. In addition, breadcrumb is displayed on header like below. So if there is no breadcrumb or the message "LSP :: connected to [texlab2:9999]", texlab seems not to be connected to Emacs. The message "LSP :: test.tex not in project or it is blacklisted" in first image also imply disconnection. image

Could you re-run the test with M-: in the tex file? If you get the message "Not in the project", you might put the directory to blacklist on the test before. Deleting .emacs.d/.lsp-session-v1 and re-open the Emacs is remove all blacklist.

(if (lsp--calculate-root (lsp-session) (buffer-file-name))
   (message "In the project")
 (message "Not in the project"))
hongyi-zhao commented 3 years ago

Put (global-company-mode +1) to your init.el if you want to use company on all buffer,

What's the meaning of +1 used above?

or put (add-hook 'TeX-mode-hook #'company-mode) for use on tex buffer.

Why can I activate lsp on tex buffer with the following:

(add-hook 'TeX-mode-hook 'lsp)

While for company-mode, I should use the following form?

(add-hook 'TeX-mode-hook #'company-mode)

I mean: why must I use the different leading special character sequences, i.e., ' and #', respectively?

Type i or I for select project. The project is saved for next time.

Wonderful. See below:

image

The result of M-x company-diag RET:

image

And the completion really works now:

image

But I still meet some strange problems: If I try to use the completion in mathematical environment, i.e, between $$, the first time it will be completed successfully:

image

If I delete the already entered result with backspace between the $$, and then re-enter the same or other mathematical symbols, the completion won't be done again, as shown below:

image

But if I am not in mathematics/equation environments, the problem will only appear rarely.

In addition, I only want to trigger the mathematics symbols completion in equation environments, and other LaTeX commands in normal writing environments. Is this possible? At the same time, I want to have the ispell based (on-the-fly) spell checker.

How to solve these problems / achieve these goals?

Regards, HY

ROCKTAKEY commented 3 years ago

What's the meaning of +1 used above?

Positive value means turning on the mode, while non-positive value means turning off. Actually, you can omit +1, because default value of the argument is positive value. Just preference. This is applicable for all minor-modes.

(global-company-mode)
;is same as 
(global-company-mode +1)

On the other hand, If you call global-minor-mode interactively, it toggles mode by default.

Why can I activate lsp on tex buffer with the following: (add-hook 'TeX-mode-hook 'lsp) While for company-mode, I should use the following form? (add-hook 'TeX-mode-hook #'company-mode) I mean: why must I use the different leading special character sequences, i.e., ' and #', respectively?

'symbol is expanded to (quote symbol), while #'symbol to (function symbol). so using #' is better when you want to treat the symbol as a function (though using ' does not lead any error and it works well). About second argument of add-hook, we should pass function, so using #' is better. We should write like (add-hook 'TeX-mode-hook #'lsp) or (add-hook 'TeX-mode-hook #'company-mode).

If I delete the already entered result with backspace between the $$, and then re-enter the same or other mathematical symbols, the completion won't be done again, as shown below:

Umm, sorry, I have no idea. it seems to be bug of texlab or lsp-mode.

In addition, I only want to trigger the mathematics symbols completion in equation environments, and other LaTeX commands in normal writing environments. Is this possible?

Probably it is impossible. You can only request it to texlab author.

At the same time, I want to have the ispell based (on-the-fly) spell checker.

It seems to be possible. Search with query like flyspell emacs.

hongyi-zhao commented 3 years ago

This is applicable for all minor-modes.

Why isn't it applicable for all major-modes?

About second argument of add-hook, we should pass function,

Thank you, I confirmed it with the following: M-x describe-functino R add-hook R.

add-hook is a compiled Lisp function in ‘subr.el’.

(add-hook HOOK FUNCTION &optional DEPTH LOCAL)

As for other questions, I'll try to communicate with appropriated developers and refer back to the questions and clues here, if necessary.

hongyi-zhao commented 3 years ago
2\. Ensure that the tex file is in project. **_In the tex file_**, push `M-:`, paste below code and send RET. When "Not in the project" is messaged, the file is not in the project. please put the file to project, such as dir managed by git.

But based on current tries, even the tex file isn't managed by git, texlab still works smoothly.

werner@X10DAi:~/test$ ls 
 auto  '#test.tex#'   test.tex   test.tex~
werner@X10DAi:~/test$ git status 
fatal: not a git repository (or any of the parent directories): .git

image

And at the same time, it works perfect without the use of the auxiliary tools like projectile.

ROCKTAKEY commented 3 years ago

Why isn't it applicable for all major-modes?

Because major-mode cannot be turned off. All buffer must have one major-mode. So All we can do is turning to other major-mode.

But based on current tries, even the tex file isn't managed by git, texlab still works smoothly.

It is because you registered /home/werner/ as a project. Actually, a project dont have to be git repository. Just one of a ways of telling "This dir is a project." You should register each repository (not only git repository, just unit of your files) as a project, because texlab has some features affecting some other files in the project. You can reset project registration by removing .lsp-session-v1 from your .emacs.d and rerunning your Emacs.

hongyi-zhao commented 3 years ago

Thank you for your explanation. See the following content of the .lsp-session-v1 file:

werner@X10DAi:~/.emacs.d$ cat .lsp-session-v1 
#s(lsp-session ("/home/werner") nil #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data ()) #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data ()) #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8125 data ()))

What is the specific meaning of these numbers in this file?

hongyi-zhao commented 3 years ago

In summary, based on the valuable discussion here, I figured out the company, texlab, lsp-mode, and lsp-latex based completion, as well as the corresponding configuration with company, texlab, and eglot. I put all the related successfully tested configurations here for those who need it.

;; Save this configuation and then test it as below:
;$ emacs -q --load ~/.emacs.d/init.company-texlab-eglot-lsp-mode-lsp-latex
;;Bootstrap straight
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
      (bootstrap-version 5))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))
(straight-use-package 'use-package)
(setq straight-use-package-by-default t)

;Using AUCTeX from local Git repo without installation
;https://github.com/raxod502/straight.el/issues/800#issuecomment-862165317
(straight-use-package
 `(auctex :type git :host nil :repo "https://git.savannah.gnu.org/git/auctex.git"
    :pre-build ,(pcase system-type
                (`berkeley-unix '("gmake"))
                (_ '(
                    `("bash" "-c" "cd" ,(straight--repos-dir "auctex"))
                    ("./autogen.sh")
                    ("./configure" "--without-texmf-dir" "--with-lispdir=.") 
                    ("make")
                    )))))

     (setq TeX-data-directory (straight--repos-dir "auctex")
           TeX-lisp-directory TeX-data-directory)                   

; Or set the following variable via custom-set-variables in the opened buffer by the following command.
; M-x describe-variable RET preview-TeX-style-dir RET
;`(preview-TeX-style-dir ,(concat ".:" (straight--repos-dir "auctex") "latex:"))
(setq preview-TeX-style-dir (concat ".:" (straight--repos-dir "auctex") "latex:"))

(load "auctex.el" nil t t) 
(load "preview-latex.el" nil t t)
(setq TeX-auto-save t)
(setq TeX-parse-self t)
(setq-default TeX-master nil)

;;; Method 1
;;; Based on eglot and texlab
;(use-package eglot
;  :hook 
;  ((TeX-mode . eglot-ensure))
;  :config
;  (add-to-list 'eglot-server-programs
;             '((latex-mode tex-mode context-mode texinfo-mode bibtex-mode) . ("texlab"))))

;;; Method 2
;;; Based on lsp-mode, texlab, and lsp-latex
(use-package lsp-mode
 :hook
 (TeX-mode . lsp))

(use-package lsp-latex
  :straight (:host github :repo "ROCKTAKEY/lsp-latex"))

;;; company configuration
(use-package company
  :hook
  (TeX-mode . company-mode)
  :custom
  (setq company-idle-delay 0) 
  (setq company-minimum-prefix-length 1))
ROCKTAKEY commented 2 years ago

Sorry for late reply and thanks for your summation.

What is the specific meaning of these numbers in this file?

.lsp-session-v1 file is just inner value such as cache of project. So we, LSP-client users, do not have to know it. If you want to know, see the definition of lsp-session struct in lsp-mode. .lsp-session-v1 contains lsp-sesstion struct.

hongyi-zhao commented 2 years ago

Thank you for your explanation.