diff --git a/redvault_el_rs/src/redvai-mini.el b/redvault_el_rs/src/redvai-mini.el new file mode 100644 index 0000000..6effd5a --- /dev/null +++ b/redvault_el_rs/src/redvai-mini.el @@ -0,0 +1,202 @@ +;;; redvai.el --- Description -*- lexical-binding: t; -*- +;; +;; Copyright (C) 2024 Tristan Druyen +;; +;; Filename: redvai-mini.el +;; Author: Tristan Druyen +;; Maintainer: Tristan Druyen +;; Created: Oktober 09, 2024 +;; Modified: November 27, 2024 +;; Version: 0.0.1 +;; Keywords: convenience extensions tools +;; Homepage: https://git.vlt81.de/vault81/redvault-ai +;; Package-Requires: ((emacs "25.0")) +;; +;; This file is not part of GNU Emacs. +;; +;;; Commentary: +;; - only tested on bleeding-edge emacs, might work on older versions +;; - needs to be compiled with dynamic module support +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Change log: +;; +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; 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, 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 this program; see the file COPYING. If not, write to +;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth +;; Floor, Boston, MA 02110-1301, USA. +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;;; Code: + + +(require 's) +(require 'cl-lib) + +(defface redvai-overlay-face + '((t :inherit shadow)) + "Face for redvai overlay") + +(defun redvai--set-overlay-text (ov completion) + "Set overlay OV with COMPLETION." + (save-restriction + (widen) + (let* ((suffix-replace-chars (overlay-get ov 'suffix-replace-chars)) + (p-completion (propertize completion 'face 'redvai-overlay-face))) + (add-text-properties 0 1 '(cursor 1) p-completion) + (overlay-put ov 'after-string p-completion) + (overlay-put ov 'display (char-to-string ?\u200B)) ;; \u200B is a zero-width space. Trick to fix the wrong character inserted position. + (move-overlay ov (point) (+ (point) 1)) + (overlay-put ov 'completion completion)))) + +(defvar-local redvai--overlay nil + "Overlay for redvai completion.") + + +(defconst redvai-completion-map (make-sparse-keymap) + "Keymap for Redvai completion overlay.") + + +(defun redvai--get-overlay () + "Create or get overlay for redvai." + (unless (overlayp redvai--overlay) + (setq redvai--overlay (make-overlay 1 1 nil nil t)) + (overlay-put redvai--overlay 'keymap redvai-completion-map) + (overlay-put redvai--overlay 'after-string "")) + redvai--overlay) + + +(defun redvai--overlay-visible () + "Return t if the overlay is visible." + (and (overlayp redvai--overlay) + (overlay-buffer redvai--overlay))) + +(defun redvai--test-overlay () + "Bla" + (interactive) + (redvai--set-overlay-text (redvai--get-overlay) "Test123")) + +(defun redvai-complete () + (interactive) + ;; TODO call into module + ;; (redvai--set-overlay-text (redvai--get-overlay) "Test123") + ) + + +(defun redvai--clear-overlay () + (message "%S" "Cleared") + (when (redvai--overlay-visible) + (delete-overlay redvai--overlay))) + +(defun redvai-dismiss () + "Clear overlay." + (interactive) + (redvai--clear-overlay)) + +(defun redvai--current-completion () + (substring-no-properties (overlay-get (redvai--get-overlay) 'after-string))) + +(defun redvai-accept-completion () + "Bla" + (interactive) + (when (redvai--overlay-visible) + (insert (redvai--current-completion)) + (clear-overlay))) + +;;; redvai-mode + + +(defun redvai--self-insert (command) + "Handle the case where the char just inserted is the start of the completion. +If so, update the overlays and continue. COMMAND is the +command that triggered `post-command-hook'." + (when (and (eq command 'self-insert-command) + (redvai--overlay-visible)) + (let* ((ov redvai--overlay) + (completion (redvai--current-completion))) + ;; The char just inserted is the next char of completion + (when (eq last-command-event (elt completion 0)) + (if (= (length completion) 1) + ;; If there is only one char in the completion, accept it + (progn + (overlay-put ov 'completion "") + (redvai-accept-completion)) + (redvai--set-overlay-text ov (substring completion 1))))))) + + +(defcustom redvai-idle-delay 0.2 + "Time in seconds to wait before starting completion. + Complete immediately if set to 0. + Disable idle completion if set to nil." + :type '(choice + (number :tag "Seconds of delay") + (const :tag "Idle completion disabled" nil)) + :group 'redvai) + + +(defun redvai--mode-enter () + "Set up redvai mode when entering." + (add-hook 'post-command-hook 'redvai--post-command nil 'local)) + +(defun redvai--mode-exit () + "Clean up redvai mode when exiting." + (remove-hook 'post-command-hook #'redvai--post-command 'local)) + +(defun redvai-turn-on-unless-buffer-read-only () + "Turn on `redvai-mode' if the buffer is writable." + (unless buffer-read-only + (redvai-mode 1))) + + +(defun redvai--post-command-debounce (buffer) + "Complete in BUFFER." + (when (and (buffer-live-p buffer) + (equal (current-buffer) buffer) + redvai-mode) + (redvai-complete))) + + +(defun redvai--post-command () + "Complete in `post-command-hook' hook." + (when (and this-command + (not (and (symbolp this-command) + (or + (s-starts-with-p "redvai-" (symbol-name this-command)) + (redvai--self-insert this-command))))) + (redvai-dismiss) + (when redvai--post-command-timer + (cancel-timer redvai--post-command-timer)) + (setq redvai--post-command-timer + (run-with-idle-timer redvai-idle-delay + nil + 'redvai--post-command-debounce + (current-buffer))))) + +(advice-add 'keyboard-quit :after #'redvai-dismiss) + +;;;###autoload +(define-minor-mode redvai-mode + "Minor mode for Redvai." + :init-value nil + :lighter " Redvai" + (redvai-dismiss) + (if redvai-mode + (redvai--mode-enter) + (redvai--mode-exit))) + +(provide 'redvai) +;;; redvai.el ends here