;;; init-packages.el --- Extensiones/paquetes instalados y su configuración 	-*- lexical-binding: t -*-

;; Author: kj <webmaster@outcontrol.net>
;; URL: https://git.kj2.me/kj/confi-emacs-actual

;;; Commentary:

;; Aquí se encuentran los paquetes de uso general.
;;
;; Aquellos de uso más específico, por ejemplo, los que
;; pertenecen a un lenguaje de programación en específico
;; estarán en el respectivo archivo de configuración
;; para dicho uso específico.

;;; Code:

;; Mejora del reemplazo
(use-package anzu
  :defer t
  :bind (([remap query-replace] . anzu-query-replace)
         ([remap query-replace-regexp] . anzu-query-replace-regexp)))

;; Intercamiar buffers de lugar
(use-package buffer-move
  :defer t
  :bind (("M-S-<up>" . buf-move-up)
         ("M-S-<down>" . buf-move-down)
         ("M-S-<left>" . buf-move-left)
         ("M-S-<right>" . buf-move-right))
  )

;; Mostrar la ayuda de eldoc/documentación en un childframe
(use-package eldoc-box
  :defer t
  :bind ("<f1>" . eldoc-box-help-at-point))

;; Seleccionar por regiones (similar a mark-sexp, pero toma en cuenta hacia atrás del cursor también)
(use-package expand-region
  :defer t
  :bind ("C-+" . er/expand-region))

;; Major mode para archivos CSV
(use-package csv-mode
  :defer t
  :hook ((csv-mode . csv-align-mode)
         (csv-mode . csv-header-line))
  )

;; Visor de documentos de emacs (soporta de todo: epub, pdf, odt, docx, cbz, etc.)
(use-package doc-view
  :defer t
  :hook
  (doc-view-mode . (lambda ()
                       (display-line-numbers-mode 0)))
  :ensure nil)

;; Un bonito y sencillo panel de inicio
(use-package dashboard
  :defer t
  :init
  (dashboard-setup-startup-hook)
  :hook
  (dashboard-after-initialize . (lambda ()
                    "Refrescamos el dashboard con la agenda luego de cargar todo"
                    (setq dashboard-items '(
                                            ;; (recents . 10)
                                            (agenda . 10)
                                            ))
                    (dashboard-refresh-buffer)
                    ))
  :config
  (setq dashboard-set-file-icons t
        dashboard-set-heading-icons t
        dashboard-set-file-icons t
        dashboard-week-agenda nil
        dashboard-agenda-time-string-format "%Y-%m-%d %H:%M")
  (setq dashboard-startup-banner
        (expand-file-name "duck.svg" user-emacs-directory))
   (setq dashboard-items '())
  )

;; Coloca en emacs la documentacón distribuída por devdocs.io
(use-package devdocs
  :defer t)

;; Sidebar a la derecha con los archivos
(use-package dired-sidebar
  :defer t
  :hook (dired-mode . hl-line-mode)
  :ensure t
  :bind ([f9] . dired-sidebar-toggle-sidebar)
  :commands (dired-sidebar-toggle-sidebar)
  :config
  (setq dired-sidebar-theme 'nerd
        ;; dired-sidebar-should-follow-file t
        ;; dired-sidebar-follow-file-idle-delay 0.5
        ))

;; Mover líneas o regiones
(use-package drag-stuff
  :defer t
  :hook
  (elpaca-after-init . drag-stuff-global-mode)
  :config
  (drag-stuff-define-keys))

;; La línea bonita esa de abajo
(use-package doom-modeline
  :defer t
  :ensure t
  :hook (elpaca-after-init . doom-modeline-mode)
  :config
  (setq doom-modeline-project-detection 'auto
        doom-modeline-buffer-file-name-style 'relative-from-project
        doom-modeline-major-mode-color-icon t
        doom-modeline-buffer-modification-icon t
        doom-modeline-indent-info nil
        doom-modeline-persp-name t))

;; Resolver diferencias entre 2 archivos o versiones del mismo.
(use-package ediff
  :defer t
  :ensure nil
  :config
  (setq ediff-diff-options "")
  (setq ediff-custom-diff-options "-u")
  (setq ediff-window-setup-function 'ediff-setup-windows-plain)
  (setq ediff-split-window-function 'split-window-vertically))

;; Emparejamiento automático de comillas, paréntesis, corchetes y llaves
(use-package electric-pair
  :defer t
  :ensure nil
  :hook (elpaca-after-init . electric-pair-mode)
  :config
  (setq electric-pair-delete-adjacent-pairs nil))

;; Git Gutter - Marca a la izq. si una linea ha sido agregada, editada o eliminada desde el último commit.
(use-package git-gutter
  :defer t
  :hook
  (elpaca-after-init . global-git-gutter-mode)
  :config
  (defhydra hydra-git-gutter (:hint nil)
    "
 ^Navigation^  | ^Actions^     | ^Others^
-^-----------^-+-^----^--------+-^-------^----------
 _p_: previous | _s_: stage    | _m_:   mark
 _n_: next     | _r_: revert   | _SPC_: toggle info
-^-----------^-+-^----^--------+-^-------^----------
"
            ("p" git-gutter:previous-hunk)
            ("n" git-gutter:next-hunk)
            ("s" git-gutter:stage-hunk)
            ("r" git-gutter:revert-hunk)
            ("m" git-gutter:mark-hunkmark)
            ("SPC" git-gutter:toggle-popup-hunk))
  )

;; Visitar rápidamente viejas versiones de un archivo rápidamente
(use-package git-timemachine
  :ensure t
  :defer t)

;; Cliente LLM (ollama, chatgpt, gemini, etc.)
(use-package gptel
  :defer t
  :config
  (setq gptel-model "dolphin-llama3:latest"
        gptel-backend (gptel-make-ollama "Ollama"
                        :host "localhost:11434"
                        :stream t
                        :models '("mistral:latest" "dolphin-llama3:latest" "llama3:latest" "llava:latest"))
        gptel-default-mode 'org-mode
        gptel-prompt-prefix-alist
        '((markdown-mode . "# ")
          (org-mode . "* ")
          (text-mode . "# "))
        gptel-directives
        '((default . "Eres un LLM que vive dentro de Emacs. Responde de manera concisa.")
          (programming . "Eres un LLM y un programador profesional cuidadoso. Provee el código y solo el código como output sin ningún texto adicional, prompt o nota.")
          (programming_tutor . "Eres un LLM y un programador profesional cuidadoso. Revisa el siguiente código y realiza sugerencias concisas en español para mejorarlo.")
          (programming_explainer . "Eres un LLM y un programador profesional cuidadoso. Revisa el siguiente código y explica en español de manera concisa, su funcionamiento.")
          (programming_describer . "Eres un LLM y un programador profesional cuidadoso. Revisa el siguiente código y explica en español su funcionamiento línea a línea.")
          (writing . "Eres un LLM y un asistente de escritura. Responde de manera concisa.")
          (grammarly . "You are a large language model and professional philologist. Improve grammar and spelling.")
          (chat . "Eres un LLM y un compañero de conversación. Responde de manera concisa.")
          (traductor . "Eres un traductor de libros de informática profesional. Traduce a español tomando en cuenta los posibles tecnicismos que no deberían traducirse.")
          )
        )
  )

;; Resalta los escapes de secuencia
(use-package highlight-escape-sequences
  :defer t
  :hook (prog-mode . hes-mode)
  :config
  (setq hes-mode-alist
        `((c-mode                . ,hes-c/c++/objc-escape-sequence-re)
          (c++-mode              . ,hes-c/c++/objc-escape-sequence-re)
          (objc-mode             . ,hes-c/c++/objc-escape-sequence-re)
          (go-mode               . ,hes-c/c++/objc-escape-sequence-re)
          (php-mode              . ,hes-c/c++/objc-escape-sequence-re)
          (java-mode             . ,hes-java-escape-sequence-re)
          (clojure-mode          . ,hes-java-escape-sequence-re)
          (js-mode               . ,hes-js-escape-sequence-re)
          (js2-mode              . ,hes-js-escape-sequence-re)
          (ruby-mode             . ,hes-ruby-escape-sequence-keywords)
          (lisp-mode             . ,hes-elisp-escape-sequence-re)
          (lisp-interaction-mode . ,hes-elisp-escape-sequence-re)
          (emacs-lisp-mode       . ,hes-elisp-escape-sequence-re))
        )
  )

;; Resaltar palabras clave como TODO, FIXME, etc. en comentarios del código.
(use-package hl-todo
  :ensure (hl-todo :version (lambda (_) "3.6.0"))
  :defer t
  :hook (prog-mode . hl-todo-mode)
  :config
  (add-to-list 'hl-todo-keyword-faces '("BUG" . "#d99600")))

;; Paquete para exportar buffers de emacs a HTML
(use-package htmlize
  :defer t
  :ensure t)

;; Permite crear conjuntos de atajos.
(use-package hydra
  :defer t)

;; Mostrar lo que se está presionando en pantalla
(use-package keypression
  :defer t
  :config
  (setq keypression-use-child-frame t
      keypression-fade-out-delay 1.0
      keypression-frame-justify 'keypression-left-justified
      keypression-cast-command-name t
      keypression-cast-command-name-format "%s  %s"
      keypression-combine-same-keystrokes t
      keypression-x-offset 50
      keypression-y-offset 100
      keypression-font-face-attribute '(:width normal :height 180 :weight bold))
  )

;; Generador automatizado de archivos de licencia
(use-package license-templates
  :defer t)

;; Magia para git
(use-package magit
  :defer t)

;; Todolist en magit de todos los archivos del projecto.
(use-package magit-todos
  :defer t
  :after magit
  :config (magit-todos-mode 1))

;; Modo markdown
(use-package markdown-mode
  :defer t)

;; Multiple vterm
(use-package multi-vterm
  :defer t
  :bind* (("<f5>" . multi-vterm-dedicated-toggle)
          ("C-x tt" . multi-vterm-dedicated-toggle)
          ("C-x tf" . multi-vterm)
          ("C-x tp" . multi-vterm-project)
          ;;("<tab>" . vterm-send-tab)
          )
  :ensure t)

;; Iconos bonitos para varias cosas
(use-package nerd-icons
  :defer t)

;; Usar nerd-icons en dired
(use-package nerd-icons-dired
  :defer t
  :hook (dired-mode . nerd-icons-dired-mode))

;; Modo para leer archivos de configuración de nginx
(use-package nginx-mode
  :defer t)

;; Lector EPUB
;; (use-package nov
;;   :defer t)

;; Múltiples modos en un mismo buffer
;; (use-package polymode
;; :defer t)

;; Des-minifica / ordena el código
(use-package prettier
  :defer t)

(use-package project
  :defer t
  :ensure nil
  :config
  ;; Colocamos un título del frame más bonito y útil que el por defecto
  (setq frame-title-format
        '(
          (:eval
           (let ((project-name (kj/project-name)))
             (unless (null project-name)
               (format "[%s] " project-name))))
          "%b"
          " - Emacs")
        )
)

;; Correr el código desde el buffer de emacs
(use-package quickrun
  :defer t
  :ensure t
  :bind (:map prog-mode-map
              ("C-c C-r" . quickrun)
              ("C-c r f" . quickrun)
              ("C-c r r" . quickrun-region)
              ("C-c r R" . quickrun-replace-region)
         )
  )

;; Recentf - Guarda registro de los archivos abiertos recientemente
(use-package recentf
  :defer t
  :ensure nil
  :bind ("C-x C-r" . recentf-open-files)
  :hook (after-load-theme . recentf-mode)
  :config
  (setq recentf-save-file
        (recentf-expand-file-name (concat temp-dir "/recentf"))
        recentf-auto-cleanup 'never
        recentf-keep '(file-remote-p file-readable-p)
        recentf-max-saved-items 1000
        recentf-max-menu-items 500))

;; Busqueda rápida con ripgrep
(use-package rg
  :defer t
  ;; :hook (elpaca-after-init . rg-enable-default-bindings)
  :bind (:map rg-global-map
         ("c" . rg-dwim-current-dir)
         ("f" . rg-dwim-current-file)
         ("m" . rg-menu))
  :config
  (setq rg-group-result t
        rg-show-columns t)
  (cl-pushnew '("tmpl" . "*.tmpl") rg-custom-type-aliases))

;; Guardar la posición del cursor en un archivo para volver allí cuando se lo vuelva a abrir.
(use-package saveplace
  :ensure nil
  :defer t
  :hook
  (elpaca-after-init . (lambda()
                         (setq save-place-file (locate-user-emacs-file (concat temp-dir "/places")))
                         (save-place-mode 1)
                         ))
  )

;; Mejorando el scroll
(use-package smooth-scrolling
  :defer t
  :hook (elpaca-after-init . smooth-scrolling-mode)
  :config
  (setq mouse-wheel-scroll-amount
        '(8 ((shift) . 1) ((control) . nil)))    ; Cambia el scroll a 8 líneas a la vez, 1 cuando se preciona SHIFT y saltos de página cuando presionas CTRL
  (setq mouse-wheel-progressive-speed nil)     ; Deshabilita la velocidad progresiva del scroll (mientras más scroll haces, mas rápido va)
  )

;; Ayuda a manipular los archivos con líneas demasiado largas
(use-package so-long
  :defer t
  :ensure nil
  :bind (:map so-long-mode-map
              ("C-s"    . isearch-forward)
              ("C-r"    . isearch-backward))
  :config
  (setq so-long-variable-overrides
        '((bidi-inhibit-bpa . t)
          (bidi-paragraph-direction . left-to-right)
          (buffer-read-only . nil)
          (global-hl-line-mode . nil)
          (line-move-visual . t)
          (show-paren-mode . nil)
          (truncate-lines . nil)
          (which-func-mode . nil)))
  )

;; Mecanografía
(use-package speed-type
  :defer t
  :hook
  (speed-type-mode . (lambda ()
                       (display-line-numbers-mode 0)
                       (visual-line-mode 1)
                       (visual-fill-column-mode 1)))
  :diminish
  :config
  (setq speed-type-gb-book-list '(66867 66866 66591 57303)
        speed-type-min-chars 500
        speed-type-max-chars 600))

;; Tree-sitter :)
(use-package treesit
  :defer t
  :ensure nil
  :commands (treesit-install-language-grammar nf/treesit-install-all-languages)
  :config
  (setq treesit-language-source-alist
        '((bash       . ("https://github.com/tree-sitter/tree-sitter-bash"))
          (c          . ("https://github.com/tree-sitter/tree-sitter-c"))
          (cpp        . ("https://github.com/tree-sitter/tree-sitter-cpp"))
          (css        . ("https://github.com/tree-sitter/tree-sitter-css"))
          (go         . ("https://github.com/tree-sitter/tree-sitter-go"))
          (haskell    . ("https://github.com/tree-sitter/tree-sitter-haskell"))
          (html       . ("https://github.com/tree-sitter/tree-sitter-html"))
          (java       . ("https://github.com/tree-sitter/tree-sitter-java"))
          (javascript . ("https://github.com/tree-sitter/tree-sitter-javascript"))
          (json       . ("https://github.com/tree-sitter/tree-sitter-json"))
          (julia      . ("https://github.com/tree-sitter/tree-sitter-julia"))
          (lua        . ("https://github.com/Azganoth/tree-sitter-lua"))
          (make       . ("https://github.com/alemuller/tree-sitter-make"))
          (python     . ("https://github.com/tree-sitter/tree-sitter-python"))
          (php        . ("https://github.com/tree-sitter/tree-sitter-php" "master" "php/src"))
          (ruby       . ("https://github.com/tree-sitter/tree-sitter-ruby"))
          (rust       . ("https://github.com/tree-sitter/tree-sitter-rust"))
          (sql        . ("https://github.com/m-novikov/tree-sitter-sql"))
          (toml       . ("https://github.com/tree-sitter/tree-sitter-toml"))
          (zig        . ("https://github.com/GrayJack/tree-sitter-zig"))))
  (defun nf/treesit-install-all-languages ()
    "Install all languages specified by `treesit-language-source-alist'."
    (interactive)
    (let ((languages (mapcar 'car treesit-language-source-alist)))
      (dolist (lang languages)
	(treesit-install-language-grammar lang)
	(message "`%s' parser was installed." lang)
	(sit-for 0.75)))))

;; Cuando presionas enter en un bloque de comentario sigue el estilo del bloque.
;; (use-package vs-comment-return
;;   :ensure (:host github :repo "emacs-vs/vs-comment-return")
;;   :defer t
;;   :hook (prog-mode . vs-comment-return-mode)
;;   )

;; Mostrar el último commit que modificó la linea actual
(use-package vc-msg
  :defer t
  :bind (("C-c v" . vc-msg-show)
         ("C-c C-v" . vc-msg-show))
  )

;; Terminal
(use-package vterm
  :ensure t
  :defer t
  :config
  (setq tramp-histfile-override nil)                  ;; Dejamos que se use el history por defecto del servidor remoto
  (setq vterm-tramp-shells '(("ssh" "/bin/bash")
                             ("sshx" "/bin/bash")
                             ("docker" "/bin/bash")
                             ("podman" "/bin/bash"))) ;; Tanto docker como podman usarán bash cuado se contecte mediante tramp
  )

;; Cuando iniicias un atajo de teclas te muestra las posibilidades
(use-package which-key
  :defer t
  :hook (elpaca-after-init . which-key-mode))

;; Restaurar el estado de los frames
(use-package winner
  :ensure nil
  :defer t
  :hook (elpaca-after-init . winner-mode))

;; Emacs Start Up Profiler
(use-package esup
  :defer t)

(provide 'init-packages)
;;; init-packages.el ends here