#+PROPERTY: header-args:emacs-lisp :tangle "~/.emacs.d/config-programming.el" :comments both

* lsp
#+begin_src emacs-lisp
  (use-package lsp-mode
    :after corfu
    :commands lsp
    :config
    (setq lsp-lens-enable nil)
    (setq lsp-enable-dap-auto-configure nil)
    (setq read-process-output-max (* 1024 1024))
    (setq lsp-completion-provider :none)
    ;; (defun corfu-lsp-setup ()
    ;;   (setq-local completion-styles '(orderless)
    ;;               completion-category-defaults nil))
    ;; (add-hook 'lsp-mode-hook #'corfu-lsp-setup)
    )

  (use-package lsp-ui
    :after lsp-mode
    :bind (:map lsp-mode-map
                ("M-." . #'lsp-ui-peek-find-definitions)
                ("M-?" . #'lsp-ui-peek-find-references)
                ;;("M-p" . #'lsp-ui-peek-jump-forward)
                )
    :hook (lsp-mode . lsp-ui-mode)
    :config
    (setq lsp-ui-flycheck-enable t)
    (setq lsp-ui-flycheck-live-reporting t)
    (setq lsp-ui-doc-show-with-cursor t))

  (use-package dap-mode
    :hook ((java-mode . dap-mode)
           (java-mode . dap-ui-mode))
    :bind (:map dap-mode-map
                ("C-c h" . #'dap-hydra)
                ("C-c b" . #'dap-breakpoint-toggle)
                ("C-c d r" . #'dap-java-debug)
                ("C-c d m" . #'dap-java-debug-test-class)
                ("C-c r t" . #'mvn-test)))
#+end_src
* Yasnippets
#+BEGIN_SRC emacs-lisp
  (let ((fetcher (if (or noninteractive my-ec/at-ti) "github" "github-ssh")))
    (quelpa `(yasnippet :repo "pestctrl/yasnippet" :branch "quit-undo-tree" :fetcher ,fetcher)))
  (use-package java-snippets)
  (add-hook 'lsp-mode-hook 'yas-minor-mode)
#+END_SRC

* c++
#+begin_src emacs-lisp
  (use-package lsp-mode
    :custom
    (lsp-completion-provider :none) ;; we use Corfu!
    :init
    (defun my/lsp-mode-setup-completion ()
      (setf (alist-get 'styles (alist-get 'lsp-capf completion-category-defaults))
            '(flex))) ;; Configure flex
    :hook
    (lsp-completion-mode . my/lsp-mode-setup-completion)
    :config
    (require 'my-nprocs)
    (with-eval-after-load 'lsp-clangd
      (add-to-list 'lsp-clients-clangd-args
                   (format "-j=%d"
                           (nprocs))))

    (setq lsp-clangd-binary-path
          (executable-find "clangd"))

    (add-hook 'lsp-mode-hook
              (lambda ()
                (auto-highlight-symbol-mode -1)))

    ;; (setq lsp-disabled-clients nil)

    ;; (add-to-list 'lsp-disabled-clients '(c++-mode . ccls))
    ;; (add-to-list 'lsp-disabled-clients '(c-mode . ccls))
    ;; (add-to-list 'lsp-disabled-clients '(objc-mode . ccls))
    )

  (use-package ccls
    :after lsp-mode
    :hook
    ((c-mode c++-mode objc-mode) .
     #'my/cpp-auto-lsp)
    :init
    (setq lsp-enable-file-watchers nil)
    (defun my/cpp-auto-lsp ()
      (let ((project-root (projectile-project-p)))
        (when (and project-root
                   (file-readable-p (expand-file-name "compile_commands.json"
                                                      project-root))
                   ;; (or (lsp-workspaces)
                   ;;     (y-or-n-p "Should I start LSP? "))
                   )
          (when (string-match-p "llvm-project" project-root)
            (lls/ensure-initialized))
          (lsp))))
    :config

    (setq ccls-sem-highlight-method 'font-lock-mode)
    (setq ccls-initialization-options
          '(:index (:trackDependency 1 :threads 60)))

    (with-eval-after-load 'doom-modeline
      (advice-add #'lsp--progress-status
                  :filter-return
                  #'(lambda (result)
                      (when result
                        (concat (string-replace "%%" "%%%%" result) " ")))))

    (when my-ec/at-ti
      (add-to-list 'exec-path
                   "/db/sds/packagse2/ccls-master")
      (setq ccls-executable "/db/sds/packages2/ccls-master/ccls")))

  (use-package tree-sitter)
  (use-package tree-sitter-langs)

  ;; (when (and (boundp 'treesit-available-p)
  ;;            (treesit-available-p))
  ;;   (require 'treesit)
  ;;   (when (treesit-ready-p 'cpp)
  ;;     (require 'c-ts-mode)
  ;;     (push '(c++-mode . c++-ts-mode) major-mode-remap-alist)))
#+end_src
* Projectile
#+begin_src emacs-lisp
  (use-package projectile
    :init
    (progn
      (setq projectile-enable-caching t)
      (setq projectile-git-submodule-command nil)
      (setq projectile-completion-system 'default)

      ;; (setq counsel-projectile-switch-project-action 'projectile-vc)
      (setq projectile-switch-project-action 'projectile-dired)
      (setq projectile-require-project-root t)
      (setq projectile-indexing-method 'hybrid)
      (setq projectile-auto-update-cache nil)

      (global-set-key (kbd "C-c C-.") 'projectile-command-map)
      (global-set-key (kbd "C-c M-[ emacs-C-.") 'projectile-command-map))
    :config
    (projectile-mode)
    (add-to-list 'projectile-globally-ignored-directories
                 ".ccls")

    (when (and (null window-system)
               (not (daemonp)))
      (with-eval-after-load 'cc-mode
        (define-key c++-mode-map (kbd "C-c .") nil)
        (define-key c++-mode-map (kbd "C-c . .") #'c-set-style)
        (define-key org-mode-map (kbd "C-c .") nil)
        (define-key org-mode-map (kbd "C-c . .") #'org-time-stamp)))

    ;; Provide my own projectile-compile-project which uses
    ;; cca/projectile-compilation-dir instead of projectile-compilation-dir.
    (defvar cca/projectile-compilation-hash (make-hash-table :test 'equal)
      "Has of project roots to compilation directories")

    (defun cca/projectile-get-compilation-dir (key_dir)
      "Get the compilation directory associated with the specified root directory"
      (gethash key_dir cca/projectile-compilation-hash))

    (defun cca/projectile-set-compilation-dir (key_dir value)
      "Set the compilation directory for the specified root directory"
      (puthash key_dir value cca/projectile-compilation-hash))

    (defun cca/projectile-compilation-dir()
      "Prompts the user for a directory relative to the project root
  and returns the absolute path. It also stores the relative path
  from the current project root into projectile-compilation-dir."
      (let* ((root (projectile-project-root))
             (base-compilation-dir (or (cca/projectile-get-compilation-dir root) root))
             (full-compilation-dir (expand-file-name
                                    (read-directory-name "Build directory: " base-compilation-dir))))
        (setq projectile-project-compilation-dir (file-relative-name full-compilation-dir root))
        (cca/projectile-set-compilation-dir root full-compilation-dir)))

    (defun projectile-compile-project (arg)
      "Run project compilation command.

  Normally you'll be prompted for a compilation command, unless
  variable `compilation-read-command'.  You can force the prompt
  with a prefix ARG."
      (interactive "P")
      (let ((command (projectile-compilation-command (cca/projectile-compilation-dir))))
        (projectile--run-project-cmd command projectile-compilation-cmd-map
                                     :show-prompt arg
                                     :prompt-prefix "Compile command: "
                                     :save-buffers t))))
#+end_src
* Slime mode
#+BEGIN_SRC emacs-lisp
  (use-package slime
    :commands slime slime-switch-lisps
    :hook ((inferior-lisp-mode . inferior-slime-mode))
    :config
    (setq inferior-lisp-program (executable-find "sbcl"))

    (defun slime-switch-lisps (lisp)
      (interactive (list (completing-read "Which lisp? "
                                          '("sbcl" "ecl" "cmucl" "clozure-cl"))))
      (setq inferior-lisp-program lisp))

    (let ((clhs-file "~/quicklisp/clhs-use-local.el"))
      (if (file-exists-p clhs-file)
          (load-file clhs-file)
        (warn "clhs not installed. Please install")))

    (define-key slime-prefix-map (kbd "C-l") #'slime-load-file)
    (define-key slime-prefix-map (kbd "C-S-l") #'slime-load-system))

  (use-package slime-company
    :after slime company
    :config
    (slime-setup '(slime-fancy slime-asdf slime-company)))
#+END_SRC
* rust
#+begin_src emacs-lisp
  (use-package cargo)
  (use-package rust-mode)
  ;; For some reason, rustic is causing weird dialogue issues on
  ;; puppet's computer.
  (when (not my/puppet-p)
    (use-package rustic)
    (setq rustic-use-rust-save-some-buffers nil))
#+end_src
* golang
#+begin_src emacs-lisp
  (use-package go-mode
    :hook (go-mode . (lambda ()
                       (add-hook 'before-save-hook 'gofmt-before-save nil t)
                       (setq indent-tabs-mode nil)))
    :config
    ;; This is for lsp to work
    (add-to-list 'exec-path "~/go/bin/"))
#+end_src
* python
#+begin_src emacs-lisp
  (use-package elpy)
  ;; (elpy-enable)
  (use-package ein)
  (add-to-list 'exec-path
               "/home/benson/anaconda3/bin/" t)
#+end_src
* web stuff
#+begin_src emacs-lisp
  (use-package web-mode
    :commands web-mode
    :init
    (add-to-list 'auto-mode-alist '("\\.phtml\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.tpl\\.php\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.[agj]sp\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.as[cp]x\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.erb\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.mustache\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.djhtml\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.cshtml\\'" . web-mode))
    (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
    :config
    (setq web-mode-auto-close-style 2))

  (use-package js2-mode
    :commands js2-mode
    :init
    (add-to-list 'auto-mode-alist '("\\.js$" . js2-mode)))
#+end_src
* line-numbers
#+begin_src emacs-lisp
  (defun toggle-line-numbers ()
    (interactive)
    (if (not display-line-numbers-mode)
        (display-line-numbers-mode 1)
      (display-line-numbers-mode -1)
      (setq display-line-numbers-type
            (if (eq display-line-numbers-type t)
                'relative
              t))
      (display-line-numbers-mode 1)))
#+end_src
* Comment keys
#+begin_src emacs-lisp
  (define-prefix-command '*comment-map*)

  (require 'work-commentor)

  (define-key *comment-map* (kbd "b") #'my/banner-comment)
  (define-key *comment-map* (kbd "B") #'my/banner-select-style)
  (define-key *comment-map* (kbd "/") #'comment-region)
  (define-key *comment-map* (kbd "\\") #'uncomment-region)

  (define-key *root-map* (kbd "/") '*comment-map*)
#+end_src

* Various common files
#+begin_src emacs-lisp
  (use-package csv-mode
    :commands csv-mode
    :init
    (add-to-list 'auto-mode-alist
                 '("\\.csv$" . csv-mode)))

  (use-package yaml-mode
    :commands yaml-mode
    :init
    (add-to-list 'auto-mode-alist
                 '("\\.yaml$" . yaml-mode)
                 '("\\.yml$" . yaml-mode)))
#+end_src
* Setup convenient headers
#+begin_src emacs-lisp
  (setq auto-insert-alist
        '(((emacs-lisp-mode . "Emacs lisp mode") nil
           ";;; " (file-name-nondirectory buffer-file-name) " --- " _ " -*- lexical-binding: t -*-\n\n"

           ";; Copyright (C) " (format-time-string "%Y") " Benson Chu\n\n"

           ";; Author: Benson Chu <bensonchu457@gmail.com>\n"
           ";; Created: " (format-time-string "[%Y-%m-%d %H:%M]") "\n\n"

           ";; This file is not part of GNU Emacs\n\n"

           ";; This program is free software: you can redistribute it and/or modify\n"
           ";; it under the terms of the GNU General Public License as published by\n"
           ";; the Free Software Foundation, either version 3 of the License, or\n"
           ";; (at your option) any later version.\n\n"

           ";; This program is distributed in the hope that it will be useful,\n"
           ";; but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
           ";; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
           ";; GNU General Public License for more details.\n\n"

           ";; You should have received a copy of the GNU General Public License\n"
           ";; along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\n"

           ";;; Commentary:\n\n"

           ";;; Code:\n\n"

           "(provide '" (file-name-sans-extension (file-name-nondirectory buffer-file-name)) ")\n"
           ";;; " (file-name-nondirectory buffer-file-name) " ends here\n")
          ((lisp-mode . "Common Lisp") nil
           "(defpackage :" (file-name-sans-extension (file-name-nondirectory buffer-file-name)) "\n"
           "  (:use :cl :alexandria)\n"
           "  (:export))\n\n"

           "(in-package :" (file-name-sans-extension (file-name-nondirectory buffer-file-name)) ")")))

  (auto-insert-mode)
#+end_src
* Copilot?
#+begin_src emacs-lisp
  (quelpa '(copilot :fetcher "github" :repo "zerolfx/copilot.el" :files ("dist" "*.el")))
  ;; Run copilot-login
  (add-hook 'prog-mode-mook 'copilot-mode)
#+end_src
* llvm-lib
#+begin_src emacs-lisp
  (require 'llvm-lib)

  (define-key *root-map* (kbd "C-w") '*llvm-map*)
#+end_src
* treesit
#+begin_src emacs-lisp
  ;; (setq treesit-language-source-alist '())
  (setq treesit-font-lock-level 5)
#+end_src
* lua
#+begin_src emacs-lisp
  (use-package lua-mode)
#+end_src
* 0x0
#+begin_src emacs-lisp
  (use-package 0x0)
#+end_src
