;;; fcomp.el --- fcomp front-end -*- lexical-binding: t; -*- ;; Copyright (C) 2019 Anastasis Grammenos ;; Author: Anastasis Grammenos ;; Keywords: lisp ;; Version: 0.0.1 ;; 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 this program. If not, see . ;;; Commentary: ;; Emacs front-end for fcomp. Get it from https://ubuntos.dynu.net/git/fcomp ;;; Install: ;; git clone https://ubuntos.dynu.net/git/fcomp && cd fcomp ;; make && make install # install copies the binary under /usr/local/bin ;; In the emacs init file: ;; (add-to-list 'load-path "/your/custom/path") ;; (require 'fcomp) ;; (setq fcomp-path "/your/custom/path/fcomp") ;; (global-set-key (kbd "C-") 'fcomp-autocomplete) ;; or with use-package ;; (use-package fcomp ;; :load-path "/your/custom/path" ;; :bind (("C-" . fcomp-autocomplete)) ;; :config ;; (setq fcomp-path "/your/custom/path/fcomp")) ;;; Code: (require 'ido) (require 'subr-x) (defvar fcomp-path "/usr/local/bin/fcomp") (defvar fcomp-min-word-length 3) (defvar fcomp-extra-valid-chars "") (defvar fcomp-extra-invalid-chars "") (defun empty-string-p (string) "Return true if the string is empty or nil. Expects string." (or (null string) (zerop (length (string-trim string))))) (defun fcomp--start (query) "Initiaize fcomp variables" (setq fcomp--query query) (setq fcomp--output "")) (defun fcomp--filter (proc str) "Fill the output buffer" (let* ((fcomp-pre (if (empty-string-p (process-get proc 'input-word)) nil (format "%s" (process-get proc 'input-word))))) (setq fcomp--output (concat fcomp--output str)))) (defun fcomp--handle-output () "Handle output buffer" (let ((initial-input fcomp--query) (out-string fcomp--output) (result nil)) (if (empty-string-p fcomp--output) nil (setq result (ido-completing-read "Complete:" (remove "" (split-string fcomp--output "\n")) nil nil initial-input))) (if (empty-string-p result) (message "%s" "No completion candidates") (insert (string-remove-prefix (if (empty-string-p initial-input) (format "%s" "") (format "%s" initial-input)) result))) (setq fcomp--query "") (setq fcomp--output ""))) (defun fcomp-autocomplete () "Autocompete using fcomp.c When `thing-at-point' is a word, autocomplete it based on buffer contents. When invoked with no `thing-at-point' show a list of all possible candidates. Requires fcomp. Get it at URL `https://ubuntos.dynu.net/git/fcomp'" ;; Thanks Dan for the syntax-table trick ;; https://emacs.stackexchange.com/questions/9583/how-to-treat-underscore-as-part-of-the-word (interactive) (let ((table (copy-syntax-table (syntax-table)))) (modify-syntax-entry ?- "w" table) (with-syntax-table table (fcomp--autocomplete (thing-at-point 'word 'no-properties))))) (defun fcomp--autocomplete (word) "Start fcomp process and orchistrate it's output." (let ((term (if (empty-string-p word) (format "%s" "-a") (format "%s" word))) (input (buffer-substring-no-properties (point-min) (point-max)))) (fcomp--start word) (set-process-filter (start-process "fcomp" nil (format "%s"fcomp-path) "-w" (format "%s" fcomp-min-word-length) "-F" (format "%s" input) "-v" (format "%s" fcomp-extra-valid-chars) "-i" (format "%s" fcomp-extra-invalid-chars) term) #'fcomp--filter) (process-put (get-process "fcomp") 'input-word word) (accept-process-output (get-process "fcomp")) (fcomp--handle-output))) (provide 'fcomp) ;;; fcomp.el ends here