
Language servers provide auto completion and syntax highlighting capabilities making them essential for development.

* Lsp Mode

Lsp Mode is a package that adds language server functionalities to Emacs.

** Breadcrumb Header Line

This adds a headerline that shows the scope of where the cursor is in the code. For example if the user is in the main function, the headerline will contain main.

#+begin_src emacs-lisp
  (defun jm/lsp-mode-setup ()
    (setq lsp-headerline-breadcrumb-segments '(path-up-to-project file symbols))
    (lsp-headerline-breadcrumb-mode))
#+end_src

** Install Lsp Mode

Below I am installing the actual package and adding some basic configuration.

#+begin_src emacs-lisp
  (use-package lsp-mode
    :init (setq lsp-keymap-prefix "C-c l") ; Lsp mode prefix
    :hook (lsp-mode . jm/lsp-mode-setup)
    :commands (lsp lsp-deferred) ; Startup commands
    :config
    (lsp-enable-which-key-integration t)
    (setq lsp-enable-snippet nil))
#+end_src

** Lsp Additional Packages

#+begin_src emacs-lisp
  (use-package lsp-ui
    :hook (lsp-mode . lsp-ui-mode)
    :config
    (setq lsp-ui-sideline-enable t
          lsp-ui-show-diagnostics t
          lsp-ui-doc-enable t))
#+end_src

** Company Mode

Company is a package that automatically finds completions instead of making the user run a command for completions.

#+begin_src emacs-lisp
  (use-package company
    :after lsp-mode
    :hook (lsp-mode . company-mode)
    :bind (:map company-active-map ; Map tab to select completion
                ("<tab>" . company-complete-selection))
          (:map lsp-mode-map
                ("<tab>" . company-indent-or-complete-common)))
#+end_src

** Flycheck

#+begin_src emacs-lisp
  (use-package flycheck
    :init (global-flycheck-mode))
#+end_src

** Direnv for Nix-Shell Integration

Direnv is a program that will automatically run ~nix-shell~ when a ~.envrc~ file is found. Using the ~emacs-direnv~ package, you can more easily integrate nix into your development environment.

#+begin_src emacs-lisp
(use-package direnv
  :config
  (direnv-mode))
#+end_src

* Language Servers

This will include any language server packages and configuration.

** HTML

#+begin_src emacs-lisp
(use-package web-mode
  :defer t
  :mode ("\\.html\\'" "\\.svelte\\'")
  :hook (web-mode . lsp-deferred)
  :init
  (setq web-mode-engines-alist '(("svelte" . "\\.svelte\\'"))))
#+end_src

** JavaScript/Typescript

#+begin_src emacs-lisp
(use-package typescript-mode
  :defer t
  :mode ("\\.ts\\'" "\\.js\\'")
  :hook (typescript-mode . lsp-deferred))
#+end_src

Install the ~typescript-language-server~ through npm.

#+begin_src sh
  npm install -g typescript-language-server
#+end_src

** Python

#+begin_src emacs-lisp
(use-package python-mode
  :defer t
  :mode ("\\.py\\'")
  :hook (python-mode . lsp-deferred))
#+end_src

Install the ~python-lsp-server~ though pip.

#+begin_src sh
  pip install python-lsp-server
#+end_src

** C/C++

#+begin_src emacs-lisp
(use-package ccls
  :defer t
  :hook ((c-mode cc-mode c++-mode objc-mode cuda-mode) .
         (lambda () (require 'ccls) (lsp)))
  :config
  (setq ccls-executable "/usr/bin/ccls"))
#+end_src

Install ~ccls~ with homebrew using the following command.

#+begin_src sh
  sudo apt install ccls
#+end_src

** Golang

#+begin_src emacs-lisp
(use-package go-mode
  :defer t
  :hook (go-mode . lsp-deferred))
#+end_src

** Rust

#+begin_src emacs-lisp
(use-package rustic
  :defer t
  :hook (rust-mode . lsp-deferred)
  :init
  (let ((brew-prefix (string-trim (shell-command-to-string "brew --prefix"))))
    (when (and (memq window-system '(mac ns x)) brew-prefix (f-directory-p brew-prefix))
      (setenv "YARA_LIBRARY_PATH" (expand-file-name "lib" brew-prefix))
      (setenv "YARA_INCLUDE_DIR" (expand-file-name "include" brew-prefix)))))
#+end_src

** C# 

#+begin_src emacs-lisp
(use-package csharp-mode
  :defer t
  :hook (csharp-mode . lsp-deferred))
#+end_src

** JSON

#+begin_src emacs-lisp
(use-package json-mode
  :defer t
  :hook (json-mode . lsp-deferred))
#+end_src

** Yaml

#+begin_src emacs-lisp
(use-package yaml-mode
  :defer t
  :hook (yaml-mode . lsp-deferred))
#+end_src

** Yara

To install the corresponding LSP, you need to install ~yls~. Using the command ~pip install -U yls-yara~. Keep in mind that ~yls~ is dependent on an up to date version of ~yara-python~.

#+begin_src emacs-lisp
(use-package yara-mode
  :defer t
  :hook (yara-mode . lsp-deferred)
  :config
  (with-eval-after-load 'lsp-mode
    (add-to-list 'lsp-language-id-configuration
                 '(yara-mode . "yara"))

    (lsp-register-client
     (make-lsp-client :new-connection (lsp-stdio-connection "yls")
                      :activation-fn (lsp-activate-on "yara")
                      :server-id 'yls))))
#+end_src

** R

#+begin_src emacs-lisp
(use-package ess
  :defer t
  :hook (R-mode . lsp-deferred))
#+end_src

** Haskell

#+begin_src emacs-lisp
(use-package haskell-mode
  :defer t
  :hook (haskell-mode . lsp-deferred))

(use-package lsp-haskell
  :defer t
  :hook (lsp-literate-mode . lsp-deferred))
#+end_src

** Ebuild

Ebuild is the language used for Gentoo packages installed with the ~emerge~ utility. As this package is Gentoo specific, you will have to install it the command below:

#+begin_src bash
sudo emerge -v app-emacs/ebuild-mode
#+end_src

#+begin_src emacs-lisp
(use-package ebuild-mode
  :ensure nil
  :defer t
  :hook (ebuild-mode . lsp-deferred))
#+end_src

** Nix

Nix is the language used by NixOS and the Nix package manager.

#+begin_src emacs-lisp
(use-package lsp-nix
  :ensure lsp-mode
  :after (lsp-mode)
  :demand t
  :custom (lsp-nix-nil-formatter ["nixpkgs-fmt"]))

(use-package nix-mode
  :mode "\\.nix\\'"
  :hook (nix-mode . lsp-deferred))
#+end_src

