Skip to content

Files

Latest commit

 

History

History
1101 lines (906 loc) · 32.2 KB

development.org

File metadata and controls

1101 lines (906 loc) · 32.2 KB

Development

Configuration related to programming.

Preamble

;;; core.el  --- Cunene: My emacs configuration. -*- lexical-binding: t -*-
;; Author: Marco Craveiro <marco_craveiro@gmail.com> URL:
;; https://github.com/mcraveiro/prelude Version: 0.0.3 Keywords: convenience

;; This file is not part of GNU Emacs.

;;; Commentary:

;; General editor configuration

;;; License:

;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation; either version 3
;; of the License, or (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;; Code:

Version Control

git-commithttps://github.com/magit/magit/blob/master/lisp/git-commit.el
git-gutter-fringehttps://github.com/emacsorphanage/git-gutter-fringe
gitattributes-modehttps://github.com/magit/git-modes#gitattributes-mode
gitconfig-modehttps://github.com/magit/git-modes#gitconfig-mode
gitignore-modehttps://github.com/magit/git-modes#gitignore-mode
magithttps://github.com/magit/magit
pinentryhttps://elpa.gnu.org/packages/pinentry.html
transienthttps://github.com/magit/transient
git-messengerhttps://github.com/emacsorphanage/git-messenger

Git modes.

(use-package git-modes)

Auto-fill commit messages.

(use-package git-commit
  :hook
  (git-commit-mode . (lambda () (setq-local fill-column 72))))

Display indicators in the left fringe for Git changes.

(use-package git-gutter-fringe
  :preface
  (defun cunene/git-gutter-enable ()
    (when-let* ((buffer (buffer-file-name))
                (backend (vc-backend buffer)))
      (require 'git-gutter)
      (require 'git-gutter-fringe)
      (git-gutter-mode 1)))
  :hook
  (after-change-major-mode . cunene/git-gutter-enable)
  :config
  (define-fringe-bitmap 'git-gutter-fr:added [255] nil nil '(center t))
  (define-fringe-bitmap 'git-gutter-fr:deleted [255 255 255 255] nil nil 'bottom)
  (define-fringe-bitmap 'git-gutter-fr:modified [255] nil nil '(center t)))

(use-package git-messenger
  :bind ("C-x G" . git-messenger:popup-message)
  :config
  (setq git-messenger:show-detail t
        git-messenger:use-magit-popup t))

Major modes for Git-specific files.

;; (use-package gitattributes-mode)
;; (use-package gitconfig-mode)
;; (use-package gitignore-mode)

Magit provides Git facilities directly from within Emacs.

Magit is an interface to the version control system Git, implemented as an Emacs package. Magit aspires to be a complete Git porcelain. While we cannot (yet) claim that Magit wraps and improves upon each and every Git command, it is complete enough to allow even experienced Git users to perform almost all of their daily version control tasks directly from within Emacs. While many fine Git clients exist, only Magit and Git itself deserve to be called porcelains.

— Jonas Bernoulli

(use-package magit
  :bind
  (:map magit-file-section-map
   ("<return>" . magit-diff-visit-file-other-window)
   :map magit-hunk-section-map
   ("<return>" . magit-diff-visit-file-other-window)
   :map magit-status-mode-map
   ("M-1" . nil)
   ("M-2" . nil)
   ("M-3" . nil)
   ("M-4" . nil))
  :hook
  (magit-post-stage-hook . cunene/magit-recenter)
  :config
  (setq epg-pinentry-mode 'loopback
        magit-commit-ask-to-stage 'stage ;; do not ask to stage
        magit-display-buffer-function 'magit-display-buffer-same-window-except-diff-v1
        magit-diff-highlight-hunk-region-functions
        '(magit-diff-highlight-hunk-region-using-face)
        magit-diff-refine-hunk 'all
        magit-module-sections-nested nil
        magit-section-initial-visibility-alist
        '((modules . show) (stashes . show) (unpulled . show) (unpushed . show)))
  (add-to-list 'magit-no-confirm 'stage-all-changes)
  (add-to-list 'magit-no-confirm 'unstage-all-changes)
  (magit-add-section-hook
   'magit-status-sections-hook 'magit-insert-modules-overview 'magit-insert-merge-log)
  (magit-add-section-hook 'magit-status-sections-hook
                          'magit-insert-assume-unchanged-files nil t)
  ;; insert the hidden files section in the magit status buffer.
  (magit-add-section-hook 'magit-status-sections-hook
                          'magit-insert-skip-worktree-files nil t)
  (remove-hook 'magit-section-highlight-hook #'magit-section-highlight)
  (remove-hook 'server-switch-hook 'magit-commit-diff)
  (remove-hook 'with-editor-filter-visit-hook 'magit-commit-diff))

(use-package git-timemachine)
(defun cunene/magit-recenter ()
  "Recenter the current hunk at 25% from the top of the window."
  (when (magit-section-match 'hunk)
    (let ((top (max 0 scroll-margin (truncate (/ (window-body-height) 4)))))
      (message "%s" top)
      (save-excursion
        (magit-section-goto (magit-current-section))
        (recenter top)))))

Start pinentry in order for Emacs to be able to prompt for passphrases when necessary.

Transient is the package behind the modal maps and prefixes depicted in Magit. It is currently used by Magit only in my configuration so it will stay in this section for now.

(setq-default
 transient-history-file (cunene/cache-concat "transient/history.el")
 transient-levels-file (cunene/cache-concat "transient/levels.el")
 transient-values-file (cunene/cache-concat "transient/values.el"))

(use-package transient
  :init
  :config
  (setq transient-default-level 5)
  (setq transient-mode-line-format nil))

Automatically detect the need for smerge.

(use-package smerge-mode
  :commands smerge-mode
  :bind ("C-c '" . hydra-hsmerge/body)
  :init
  (defun cunene/maybe-enable-smerge ()
    (save-excursion
      (goto-char (point-min))
      (when (re-search-forward "^<<<<<<< " nil t)
        (smerge-mode 1))))
  (add-hook 'find-file-hook 'cunene/maybe-enable-smerge)
  (add-hook 'after-revert-hook 'cunene/maybe-enable-smerge)

  :config
  (defhydra hydra-smerge (:hint nil
                          :pre (smerge-mode 1)
                          :post (smerge-auto-leave))
    "
^Move^       ^Keep^               ^Diff^                 ^Other^
^^-----------^^-------------------^^---------------------^^-------
_n_ext       _b_ase               _<_: upper/base        _C_ombine
_p_rev       _u_pper (mine)       _=_: upper/lower       _r_esolve
^^           _l_ower (other)      _>_: base/lower        _k_ill current
^^           _a_ll                _R_efine
^^           _RET_: current       _E_diff
"
      ("n" smerge-next)
      ("p" smerge-prev)
      ("b" smerge-keep-base)
      ("u" smerge-keep-upper)
      ("l" smerge-keep-lower)
      ("a" smerge-keep-all)
      ("RET" smerge-keep-current)
      ("\C-m" smerge-keep-current)
      ("<" smerge-diff-base-upper)
      ("=" smerge-diff-upper-lower)
      (">" smerge-diff-base-lower)
      ("R" smerge-refine)
      ("E" smerge-ediff)
      ("C" smerge-combine-with-next)
      ("r" smerge-resolve)
      ("k" smerge-kill-current)
      ("q" nil "cancel" :color blue)))

Project Management

(use-package project)

Syntax Checking

(use-package flycheck :init (global-flycheck-mode))

(add-to-list 'display-buffer-alist
             `(,(rx bos "*Flycheck errors*" eos)
               (display-buffer-reuse-window
                display-buffer-in-side-window)
               (reusable-frames . visible)
               (side            . bottom)
               (window-height   . 0.2)))

Syntax Highlighting

(use-package color-identifiers-mode
  :commands color-identifiers-mode
  :config
  (add-to-list 'color-identifiers:modes-alist
               '(csharp-mode "" "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)"
                             (nil font-lock-variable-name-face tree-sitter-hl-face:variable)))
  (add-to-list 'color-identifiers:modes-alist
               '(csharp-ts-mode "" "\\_<\\([a-zA-Z_$]\\(?:\\s_\\|\\sw\\)*\\)"
                                (nil font-lock-variable-name-face tree-sitter-hl-face:variable)))
  (add-hook 'prog-mode-hook 'color-identifiers-mode))

Eglot

eglothttps://github.com/joaotavora/eglot
consult-eglothttps://github.com/mohkale/consult-eglot
(use-package eglot
  :bind (("M-RET" . eglot-code-actions)))
(use-package
  flycheck-eglot
  :init
  (global-flycheck-eglot-mode))
(use-package consult-eglot)

(use-package imenu-list
  :config
  (setq imenu-list-auto-resize t)

  (add-hook 'imenu-list-major-mode-hook
            (lambda ()
              (imenu-list-minor-mode)
              (read-only-mode)
              (hl-line-mode))))

(defun cunene/path-to-omnisharp ()
  "Returns the path to the LSP server for C#."
  (if (eq window-system 'w32)
      "c:/opt/omnisharp-roslyn/latest/omnisharp-roslyn/OmniSharp.exe"
    "/home/marco/local/omnisharp/OmniSharp.exe"))

(add-to-list 'eglot-server-programs
             `((csharp-mode csharp-ts-mode) . (,(cunene/path-to-omnisharp) "-lsp")))

;;
;; Improve performance by not logging debug info.
;; https://www.reddit.com/r/emacs/comments/1447fy2/looking_for_help_in_improving_typescript_eglot/
;;
; (fset #'jsonrpc--log-event #'ignore)

Diagrams

(use-package plantuml-mode
  :mode "\\.plantuml\\'"
  :config
  (setq plantuml-indent-level 4)
  (add-to-list 'plantuml-java-args "-DPLANTUML_LIMIT_SIZE=16384")
  (add-to-list 'plantuml-java-args "-DPLANTUML_SECURITY_PROFILE=UNSECURE")
  (setq plantuml-jar-output-type-opt "png")
  (add-hook 'plantuml-mode-hook 'whitespace-mode)
  ;; (add-to-list 'plantuml-jar-args "-Playout=elk")
  (add-to-list 'plantuml-jar-args "-v")

  (if (eq system-type 'windows-nt)
      (setq plantuml-jar-path "C:/opt/plantuml/plantuml.jar"
            plantuml-default-exec-mode 'jar)
    (setq plantuml-jar-path "/usr/share/plantuml/plantuml.jar"
          plantuml-default-exec-mode 'executable))
  (setq org-plantuml-jar-path plantuml-jar-path))

(require 'plantuml-mode)
(defun cunene/plantuml-make-diagram ()
  "Create a diagram from a PlantUML buffer."
  (interactive)
  (let* ((plantuml-diagram (buffer-file-name))
         (process-query-on-exit-flag nil)
         (plantuml-buffer-name
          (concat "PlantUML: " (file-name-nondirectory plantuml-diagram))))
    (with-current-buffer (get-buffer-create plantuml-buffer-name)
      (erase-buffer)
      (goto-char (point-max))
      (insert "Starting PlantUML "(format-time-string "%D %-I:%M %p")))
    (display-buffer plantuml-buffer-name)
    (clear-image-cache)
    ;; copied from plantuml-jar-start-process, which uses stdin (e.g. -p)
    (apply #'start-process
           "PLANTUML" plantuml-buffer-name plantuml-java-command
           `(,@plantuml-java-args
             ,plantuml-jar-path
             ,(plantuml-jar-output-type-opt plantuml-jar-output-type-opt)
             ,@plantuml-jar-args
             ,plantuml-diagram))))

(use-package flycheck-plantuml
  :ensure t
  :after (plantuml-mode flycheck)
  :init (flycheck-plantuml-setup))

(with-eval-after-load "org"
  (add-to-list 'org-src-lang-modes '("plantuml" . plantuml)))

(add-to-list 'auto-mode-alist '("\\.puml\\'" . plantuml-mode))

Parenthesis

(show-paren-mode 1)

(use-package rainbow-delimiters
  :hook ((prog-mode org-mode) . rainbow-mode)
  :config
  (add-hook 'prog-mode-hook 'rainbow-delimiters-mode))

(use-package smartparens
  :diminish
  :init
  (show-smartparens-global-mode +1)
  :config
  (setq sp-autoskip-closing-pair 'always))

(use-package rainbow-mode
  :config
  (setq rainbow-x-colors nil))

Indentation

(use-package aggressive-indent)

(defun cunene/indent-buffer ()
  "Indent entire buffer"
  (interactive)
  (indent-region (point-min) (point-max)))

Deletion

smart-hungry-deletehttps://github.com/hrehfeld/emacs-smart-hungry-delete

Delete whitespace between words, parenthesis and other delimiters in a smart (dumb) way.

(use-package smart-hungry-delete
  :bind (("<backspace>" . smart-hungry-delete-backward-char)
         ("<deletechar>" . smart-hungry-delete-forward-char))
  :defer nil ;; dont defer so we can add our functions to hooks
  :config (smart-hungry-delete-add-default-hooks))

;; replace zap-to-char functionality with the more powerful zop-to-char
(global-set-key (kbd "M-z") 'zop-up-to-char)
(global-set-key (kbd "M-Z") 'zop-to-char)

;; kill lines backward
(global-set-key (kbd "C-<backspace>") (lambda ()
                                        (interactive)
                                        (kill-line 0)
                                        (indent-according-to-mode)))

(global-set-key [remap kill-whole-line] 'crux-kill-whole-line)

Code Folding

hideshowbuilt-in
(require 'hideshow)

;; Hide the comments too when you do a 'hs-hide-all'
(setq hs-hide-comments nil)

;; Set whether isearch opens folded comments, code, or both
;; where x is code, comments, t (both), or nil (neither)
(setq hs-isearch-open 't)

(setq hs-set-up-overlay
      (defun cunene/display-code-line-counts (ov)
        (when (eq 'code (overlay-get ov 'hs))
          (overlay-put ov 'display
                       (propertize
                        (format " ... <%d>"
                                (count-lines (overlay-start ov)
                                             (overlay-end ov)))
                        'face 'font-lock-type-face)))))
(add-hook 'prog-mode-hook #'hs-minor-mode)
(require 'hideshow)

XML

;; https://emacs.stackexchange.com/questions/2884/the-old-how-to-fold-xml-question
(require 'sgml-mode)
(require 'nxml-mode)

(add-to-list 'hs-special-modes-alist
             '(nxml-mode
               "<!--\\|<[^/>]*[^/]>"
               "-->\\|</[^/>]*[^/]>"

               "<!--"
               sgml-skip-tag-forward
               nil))

(add-hook 'nxml-mode-hook 'hs-minor-mode)
(global-set-key (kbd "C-<tab>") 'hs-toggle-hiding)

(defun cunene/escape-unindent-xml (start end)
  "Convert XML into a single line, removing line breaks, etc and escape quotes.
START and END mark the region."
  (interactive "r")
  (let
      ((buffer (get-buffer-create "*decoded-content*"))
       (pipeline "xmllint -exc-c14n --no-blanks - | sed 's/\"/\\\"/g'"))
    (shell-command-on-region start end pipeline buffer)
    (set-buffer buffer)
    (switch-to-buffer-other-window buffer)))

(defun cunene/unescape-indent-xml (start end)
  "Convert escaped XML into indented XML.
START and END mark the region."
  (interactive "r")
  (let*
      ((original-contents (buffer-substring (+ start 1) (- end 1)))
       (fixed-new-lines (replace-regexp-in-string "\\\\n" "" original-contents))
       (fixed-quotes (replace-regexp-in-string "\\\\\\(.\\|\n\\)" "\\1" fixed-new-lines))
       (buffer (get-buffer-create "*formatted-content*"))
       (pipeline "xmllint.exe --format -"))
    (set-buffer buffer)
    (erase-buffer)
    (insert fixed-quotes)
    (shell-command-on-region (point-min) (point-max) pipeline buffer)
    (xml-mode)
    (switch-to-buffer-other-window buffer))
  )

(defun cunene/decode-xml (start end)
  "Base64 decodes the region and unzips it, generating an XML buffer.
START and END mark the region."
  (interactive "r")
  (let
      ((buffer (get-buffer-create "*decoded-content*"))
       (pipeline "base64 -d | openssl zlib -d | xmllint.exe --format -"))
    (shell-command-on-region start end pipeline buffer)
    (set-buffer buffer)
    (xml-mode)
    (switch-to-buffer-other-window buffer)))

(defun cunene/decode (start end)
  "Base64 decodes the region and unzips it.
START and END mark the region."
  (interactive "r")
  (let
      ((buffer (get-buffer-create "*decoded-content*"))
       (pipeline "base64 -d | openssl zlib -d"))
    (shell-command-on-region start end pipeline buffer)
    (set-buffer buffer)
    (switch-to-buffer-other-window buffer)))

FV

(use-package fv-mode
  :load-path cunene/vendor-packages)

(defun cunene/decode-fv (start end)
  "Base64 decodes the region and unzips it, generating an FV buffer.
START and END mark the region."
  (interactive "r")
  (let
      ((buffer (get-buffer-create "*decoded-content*"))
       (pipeline "base64 -d | openssl zlib -d"))
    (shell-command-on-region start end pipeline buffer)
    (set-buffer buffer)
    (fv-mode)
    (switch-to-buffer-other-window buffer)))

(defun cunene/indent-escape-fv (start end)
  "Convert escaped XML into indented FV.
START and END mark the region."
  (interactive "r")
  (let*
      ((original-contents (buffer-substring (+ start 1) (- end 1)))
       (fixed-new-lines (replace-regexp-in-string "\\\\n" "" original-contents))
       (fixed-quotes (replace-regexp-in-string "\\\\\\(.\\|\n\\)" "\\1" fixed-new-lines))
       (buffer (get-buffer-create "*formatted-content*")))
    (set-buffer buffer)
    (erase-buffer)
    (insert fixed-quotes)
    (fv-mode)
    (switch-to-buffer-other-window buffer))
  )

Json

jq-formathttps://github.com/wbolster/emacs-jq-format
jq-modehttps://github.com/ljos/jq-mode
(use-package json-mode)
(use-package jq-mode)
(with-eval-after-load "json-mode"
  (define-key json-mode-map (kbd "C-c C-j") #'jq-interactively))

;; Format JSON / JSONlines with JQ
(use-package jq-format)

;; (use-package hierarchy
;;   :ensure t)

;; (use-package json-navigator
;;   :ensure t)
(defun cunene/indent-json (start end)
  "Indent region as JSON.
START and END mark the region."
  (interactive "r")
  (let
      ((buffer (get-buffer-create "*formatted-content*"))
       (pipeline "jq ."))
    (shell-command-on-region start end pipeline buffer)
    (set-buffer buffer)
    (json-mode)
    (switch-to-buffer-other-window buffer)
    )
)

(defun cunene/unescape-indent-json (start end)
  "Convert escaped JSON into indented JSON.
START and END mark the region."
  (interactive "r")
  (let*
      ((original-contents (buffer-substring (+ start 1) (- end 1)))
       (fixed-new-lines (replace-regexp-in-string "\\\\n" "" original-contents))
       (fixed-quotes (replace-regexp-in-string "\\\\\\(.\\|\n\\)" "\\1" fixed-new-lines))
       (buffer (get-buffer-create "*formatted-content*"))
       (pipeline "jq ."))
    (set-buffer buffer)
    (erase-buffer)
    (insert fixed-quotes)
    (shell-command-on-region (point-min) (point-max) pipeline buffer)
    (json-mode)
    (switch-to-buffer-other-window buffer))
  )

Markup

(use-package markdown-mode
  :ensure t
  :bind (("C-c C-s a" . markdown-table-align))
  :mode ("\\.md$" . gfm-mode))

REST

(use-package verb
  :mode ("\\.org\\'" . org-mode)
  :config (define-key org-mode-map (kbd "C-c C-r") verb-command-map)
)

(use-package swagger-to-org)
(use-package swagg)

C/C++

;; Default these extensions to c++ mode
(add-to-list 'auto-mode-alist '("\\.h\\'" . c++-mode))
(add-to-list 'auto-mode-alist '("\\.ipp\\'" . c++-mode))

(add-hook 'c-mode-common-hook
          (lambda ()
            (c-set-offset 'innamespace 0) ;; Do not indent namespaces.
            (c-set-offset 'arglist-intro '+) ;; indent function args properly
            (c-set-offset 'arglist-cont-nonempty '+)
            (c-toggle-hungry-state 1)          ;; use hungry delete.
            (auto-fill-mode 1)                 ;; auto fill comments
            (setq c-basic-offset tab-width)
            (setq c-default-style "stroustrup")))

;; Key bindings
(eval-after-load 'cc-mode
  '(progn
     ;; Ident when moving to a new line
     (define-key c-mode-map (kbd "RET") 'reindent-then-newline-and-indent)
     ))

(use-package cmake-mode)

Statistics

(use-package ess)

C#

;; (defun cunene/csharp-ts-indent-style()
;;   "Override the built-in indentation style with some additional rules"
;;   `(
;;     ;; align function arguments to the start of the first one, offset if standalone
;;     ((match nil "argument_list" nil 1 1) parent-bol c-ts-mode-indent-offset)
;;     ((parent-is "argument_list") (nth-sibling 1) 0)
;;     ;; same for parameters
;;     ((match nil "parameter_list" nil 1 1) parent-bol c-ts-mode-indent-offset)
;;     ((parent-is "parameter_list") (nth-sibling 1) 0)
;;     ;; indent inside case blocks
;;     ((parent-is "case_statement") standalone-parent c-ts-mode-indent-offset)
;;     ;; do not indent preprocessor statements
;;     ((node-is "preproc") column-0 0)
;;     ;; append to bsd style
;;     ,@(alist-get 'bsd (csharp-ts-mode--indent-styles 'cpp))))
;; (setq c-ts-mode-indent-style #'fa/c-ts-indent-style)

(use-package csharp-mode
  :config
  (defun cunene/csharp-mode-setup ()
    (flycheck-mode)
    (c-toggle-hungry-state 1)
    (setq indent-tabs-mode nil)
    (setq c-syntactic-indentation t)
    (c-set-style "ellemtel")
    (setq c-basic-offset 4)
    (setq truncate-lines t)
    (setq tab-width 4)
    (setq evil-shift-width 4))
  (add-hook 'csharp-mode-hook 'cunene/csharp-mode-setup t))

(add-to-list 'major-mode-remap-alist '(csharp-mode . csharp-ts-mode))

(add-hook 'csharp-ts-mode-hook
          (lambda ()
            (setq csharp-ts-mode--indent-rules
                  `((c-sharp
                     ,@(alist-get 'c-sharp csharp-ts-mode--indent-rules)
                     ((parent-is "parameter_list") first-sibling 1)
                     ((parent-is "member_access_expression") parent-bol csharp-ts-mode-indent-offset))))))


(defun csharp-hs-forward-sexp (&optional arg)
  "I set hs-forward-sexp-func to this function.

I found this customization necessary to do the hide/show magic in C#
code, when dealing with region/endregion. This routine
goes forward one s-expression, whether it is defined by curly braces
or region/endregion. It handles nesting, too.

The forward-sexp method takes an arg which can be negative, which
indicates the move should be backward.  Therefore, to be fully
correct this function should also handle a negative arg. However,
the hideshow.el package never uses negative args to its
hs-forward-sexp-func, so it doesn't matter that this function does not
do negative numbers.

The arg can also be greater than 1, which means go forward
multiple times. This function doesn't handle that EITHER.  But
again, I haven't see that as a problem."

  (message "csharp-hs-forward-sexp, (arg %d) (point %d)..."
           (if (numberp arg) arg -1)
           (point))

  (let ((nestlevel 0)
        (mark1 (point))
        (done nil)
        )

    (if (and arg (< arg 0))
        (message "negative arg (%d) is not supported..." arg)

      ;; else, we have a positive argument, hence move forward.
      ;; simple case is just move forward one brace
      (if (looking-at "{")
          (forward-sexp arg)

        ; The more complex case is dealing with a "region/endregion" block.
        ; We have to deal with nested regions!
        (and
         (while (not done)
           (re-search-forward "^[ \\t]*#[ \\t]*\\(region\\|endregion\\)\\b"
                              (point-max) 'move)
           (cond

            ((eobp))                    ; do nothing if at end of buffer

            ((and
              (match-beginning 1)
              ;; if the match is longer than 6 chars, we know it is "endregion"
              (if (> (- (match-end 1) (match-beginning 1)) 6)
                  (setq nestlevel (1- nestlevel))
                (setq nestlevel (1+ nestlevel))
                )
              )))

           (setq done (not (and (> nestlevel 0) (not (eobp)))))

           )                            ; while

         (if (= nest 0)
             (goto-char (match-end 2)))

         )
        )
      )
    )
  )

(unless (assoc 'csharp-mode hs-special-modes-alist)
          (push '(csharp-mode
                  ; "\\(^\\s*#\\s*region\\b\\)\\|{"      ; regexp for start block DID NOT WORK
                  "\\(^[ \\t]*#[ \\t]*region\\b\\)\\|{"  ; regexp for start block

                  ; "\\(^\\s*#\\s*endregion\\b\\)\\|}"   ; regexp for end block NO WORKY!
                  "\\(^[ \\t]*#[ \\t]*endregion\\b\\)\\|}"   ; regexp for end block

                  "/[*/]"                                ; regexp for comment start

                  csharp-hs-forward-sexp                 ; hs-forward-sexp-func
                  hs-c-like-adjust-block-beginning       ;c-like adjust (1 char)
                  ;csharp-hs-adjust-block-beginning      ;csharp adjust ?
                  )
                hs-special-modes-alist)
          )

(use-package csproj-mode)
(use-package sln-mode
  :load-path cunene/vendor-packages)
(use-package sharper
  :demand t
  :config
  (add-to-list 'auto-mode-alist '("\\.sln\\'" . sln-mode))
  :bind
  ("C-c n" . sharper-main-transient))

Clojure

(use-package clojure-mode)
(use-package inf-clojure)

Protobuf

(use-package protobuf-mode)

Terraform

(use-package terraform-mode)

Docker

dockerfilehttps://github.com/spotify/dockerfile-mode
dockerhttps://github.com/Silex/docker.el
(use-package dockerfile-mode)

(use-package docker
  :ensure t
  :bind ("C-c d" . docker))

Doxymacs

doxymacshttps://github.com/gittiver/doxymacs

TODO: for some reason we do not trigger the mode with /**, it seems to require /***, which is not in accordance with doxygen syntax.

(use-package doxymacs
  :load-path cunene/vendor-packages
  :config
  ;; syntax highlighting for doxygen keywords.
  (defun cunene/doxymacs-font-lock-hook ()
    (if (or (eq major-mode 'c-mode) (eq major-mode 'c++-mode))
        (doxymacs-font-lock)))
  (add-hook 'font-lock-mode-hook 'cunene/doxymacs-font-lock-hook)

  ;; start doxymacs mode in C/C++
  (add-hook 'c-mode-common-hook 'doxymacs-mode))

Compilation

(global-set-key (kbd "C-c c") 'compile)

;; automatically scroll the output
(setq compilation-scroll-output t)

;; reuse existing frame.
(setq display-buffer-reuse-frames t)

;; kill ongoing compilation
(setq compilation-always-kill  t)

;; save buffers whenc compiling without asking
(setq compilation-ask-about-save nil)

;; Compilation from Emacs. From prelude.
(defun cunene/colorize-compilation-buffer ()
  "Colorize a compilation mode buffer."
  (interactive)
  ;; we don't want to mess with child modes such as grep-mode, ack, ag, etc
  (when (eq major-mode 'compilation-mode)
    (let ((inhibit-read-only t))
      (ansi-color-apply-on-region (point-min) (point-max)))))

(require 'ansi-color)
(setq compilation-filter-hook nil)
;; (add-hook 'compilation-filter-hook #'cunene/colorize-compilation-buffer)

(defun cunene/recompile-quietly ()
  "Re-compile without changing the window configuration."
  (interactive)
  (save-window-excursion
    (recompile)))

Lisp

persistent-scratchhttps://github.com/Fanael/persistent-scratch
(use-package persistent-scratch
  :config
  (setq persistent-scratch-save-file
        (cunene/cache-concat "scratch/persistent-scratch"))
  (persistent-scratch-setup-default))

Mustache

mustachehttps://github.com/mustache/emacs
(use-package mustache-mode
  :ensure t)

(use-package mustache
  :ensure t
  :config)

SQL

sql-clickhousehttps://github.com/rschwarz/sql-clickhouse
(use-package sql-clickhouse)

Yaml

yaml-modehttps://github.com/yoshiki/yaml-mode
(use-package yaml-mode)

CSV

(use-package csv-mode
  :hook
  (csv-mode . (lambda ()
                (csv-align-mode)
                (csv-header-line)
                (hl-line-mode)
                (read-only-mode))))

GPT

(use-package chatgpt-shell
  :custom
  ((chatgpt-shell-openai-key
    (lambda ()
      (auth-source-pick-first-password :host "api.openai.com")))))

(use-package llama-cpp)

(use-package ellama
  :init
  (setopt ellama-language "English")
  (require 'llm-ollama)
  (setopt ellama-providers
          '(("llama3" . (make-llm-ollama
                         :chat-model "llama3" :embedding-model "llama3"))
            ("phi3" . (make-llm-ollama
                         :chat-model "phi3" :embedding-model "phi3"))
            ("codellama" . (make-llm-ollama
                            :chat-model "codellama:7b" :embedding-model "codellama:7b"))
            ("codestral" . (make-llm-ollama
                            :chat-model "codestral:latest" :embedding-model "codestral:latest"))
            ("codeqwen" . (make-llm-ollama
                           :chat-model "codeqwen:latest" :embedding-model "codeqwen:latest"))
            ("gemma2" . (make-llm-ollama
                         :chat-model "gemma2" :embedding-model ":gemma2"))
            ("qwen2" . (make-llm-ollama
                         :chat-model "qwen2:latest" :embedding-model ":qwen2"))
            ("mistral" . (make-llm-ollama
                          :chat-model "mistral:latest" :embedding-model ":mistral"))
            ))
  )

Eldoc

(setq eldoc-echo-area-use-multiline-p nil)
(use-package eldoc-box)

HA Proxy

haproxy-modehttps://github.com/port19x/haproxy-mode
(use-package haproxy-mode)

Postamble

;;; core.el ends here