1
0
mirror of https://codeberg.org/cage/tinmop/ synced 2024-12-14 22:54:02 +01:00

- allowed selecting a suggestion from suggestion-window;

- highlighted matching characters in suggestion window.
This commit is contained in:
cage 2021-07-22 14:59:29 +02:00
parent 677a6bac43
commit 218cd141e4
7 changed files with 220 additions and 35 deletions

View File

@ -388,6 +388,10 @@ suggestions-window.background = blue
suggestions-window.foreground = yellow
suggestions-window.selected.foreground = black
suggestions-window.selected.background = #ffa100
suggestions-window.height = 1/4
# the directive belows configure the window at the very bottom of the

View File

@ -370,7 +370,7 @@ be either `:keybinding' or `:string'. the former for key command the latter for
(setf (error-message object) nil))
(defun move-suggestion-page (win offset)
"Paginate win (suggestion window) by offset, will not go past the numer of pages."
"Paginate win (suggestion window) by offset, will not go past the number of pages."
(with-accessors ((suggestions-win suggestions-win)) win
(when suggestions-win
(with-accessors ((current-page suggestions-window:current-page)
@ -386,6 +386,57 @@ be either `:keybinding' or `:string'. the former for key command the latter for
(defun move-suggestion-page-right (win)
(move-suggestion-page win 1))
(defun select-suggestion (win offset)
"Paginate win (suggestion window) by offset, will not go past the number of pages."
(with-accessors ((suggestions-win suggestions-win)) win
(when suggestions-win
(with-accessors ((current-page suggestions-window:current-page)
(paginated-info suggestions-window:paginated-info)
(selected-item-row-index complete-window:selected-item-row-index)
(selected-item-column-index complete-window:selected-item-column-index))
suggestions-win
(incf selected-item-row-index offset)
(let* ((columns (elt paginated-info current-page))
(columns-count (length columns))
(column (elt columns selected-item-column-index))
(rows-count (length column)))
(cond
((< selected-item-row-index 0)
(decf selected-item-column-index)
(when (< selected-item-column-index 0)
(setf selected-item-column-index
(1- (length columns))))
(let* ((previous-column (elt columns selected-item-column-index))
(previous-column-size (length previous-column)))
(setf selected-item-row-index (1- previous-column-size))))
((>= selected-item-row-index rows-count)
(setf selected-item-row-index complete-window:+starting-item-index+)
(setf selected-item-column-index
(+ complete-window:+starting-item-index+
(rem (1+ selected-item-column-index) columns-count))))))))))
(defun select-suggestion-next (win)
(select-suggestion win -1))
(defun select-suggestion-previous (win)
(select-suggestion win 1))
(defun insert-selected-suggestion (win)
(with-accessors ((suggestions-win suggestions-win)
(command-line command-line)) win
(when suggestions-win
(with-accessors ((current-page suggestions-window:current-page)
(paginated-info suggestions-window:paginated-info)
(selected-item-row-index complete-window::selected-item-row-index)
(selected-item-column-index complete-window::selected-item-column-index))
suggestions-win
(let* ((columns (elt paginated-info current-page))
(column (elt columns selected-item-column-index))
(suggestion (trim-blanks (elt column selected-item-row-index))))
(setf command-line suggestion)
(move-point-to-end win command-line)
(win-hide suggestions-win))))))
(defun fire-user-input-event (win)
"Generates an event to notify that the user inserted an input on the
command line."
@ -423,10 +474,16 @@ command line."
(set-history-most-recent command-window prompt)))
(remove-messages command-window)
(cond
((eq :control-left event)
((eq :alt-left event)
(move-suggestion-page-left command-window))
((eq :control-right event)
((eq :alt-right event)
(move-suggestion-page-right command-window))
((eq :alt-up event)
(select-suggestion-next command-window))
((eq :alt-down event)
(select-suggestion-previous command-window))
((eq :alt-i event)
(insert-selected-suggestion command-window))
((eq :backspace event)
(setf command-line (delete-at-point command-window command-line :direction :left))
(show-candidate-completion command-window))

View File

@ -16,48 +16,118 @@
(in-package :complete-window)
(define-constant +starting-item-index+ 0)
(defclass complete-window (suggestions-window)
()
((selected-item-row-index
:initform +starting-item-index+
:accessor selected-item-row-index)
(selected-item-column-index
:initform +starting-item-index+
:accessor selected-item-column-index)
(pagination-info-matched
:initform nil
:initarg :paginated-info-matched
:accessor paginated-info-matched)
(foreground-selected-item
:initform nil
:initarg :foreground-selected-item
:accessor foreground-selected-item)
(background-selected-item
:initform nil
:initarg :background-selected-item
:accessor background-selected-item))
(:documentation "A window to shows the possible completion for an
user input"))
(defmethod calculate ((object complete-window) dt)
(declare (ignore object dt)))
(defmethod refresh-config :after ((object complete-window))
(with-accessors ((foreground-selected-item foreground-selected-item)
(background-selected-item background-selected-item)) object
(multiple-value-bind (bg fg)
(swconf:suggestion-window-selected-item-colors)
(setf foreground-selected-item fg
background-selected-item bg)
object)))
(defmethod update-suggestions ((object complete-window) hint &key &allow-other-keys)
"List the possible expansion of `hint' using the function
`complete:*complete-function*'."
(with-accessors ((paginated-info paginated-info)) object
(multiple-value-bind (candidates common-prefix)
(funcall complete:*complete-function* hint)
(when candidates
(when-let ((batches (text-utils:box-fit-multiple-column candidates
(- (win-width object) 2)
(- (win-height object)
+box-height-diff+))))
(setf paginated-info batches)
(values candidates common-prefix))))))
(flet ((partitions (template data)
(when data
(let ((ct 0))
(loop for page in template
collect
(loop for column in page
collect
(loop for row in column
collect
(prog1
(elt data ct)
(incf ct)))))))))
(with-accessors ((paginated-info paginated-info)
(paginated-info-matched paginated-info-matched)) object
(multiple-value-bind (candidates common-prefix underline-char-indices)
(funcall complete:*complete-function* hint)
(when candidates
(let* ((batches (text-utils:box-fit-multiple-column candidates
(- (win-width object) 2)
(- (win-height object)
+box-height-diff+)))
(padding-size (- (length candidates)
(length underline-char-indices)))
(padding (when (> padding-size 0)
(make-list padding-size :initial-element nil)))
(underline-batch (partitions batches (append underline-char-indices padding))))
(setf paginated-info batches)
(setf paginated-info-matched underline-batch)
(values candidates common-prefix underline-batch)))))))
(defmethod draw :after ((object complete-window))
(with-accessors ((keybindings-tree keybindings-tree)
(paginated-info paginated-info)
(current-page current-page)) object
(with-accessors ((keybindings-tree keybindings-tree)
(paginated-info paginated-info)
(paginated-info-matched paginated-info-matched)
(current-page current-page)
(selected-item-row-index selected-item-row-index)
(selected-item-column-index selected-item-column-index)
(foreground-selected-item foreground-selected-item)
(background-selected-item background-selected-item)) object
(when-window-shown (object)
(win-clear object :redraw nil)
(win-box object)
(when paginated-info
(loop
for column in (elt paginated-info current-page)
with column-count = 1
do
(let ((column-size (length (first column))))
(loop
for row in column
with row-count = 1 do
(print-text object row column-count row-count)
(incf row-count))
(incf column-count column-size)))
(draw-pagination-info object))
(let ((columns (elt paginated-info current-page))
(indices-matched (elt paginated-info-matched current-page))
(matched-attributes (combine-attributes (attribute-bold)
(attribute-underline))))
(loop
for column in columns
for column-indices in indices-matched
for column-count from 0
with column-offset = 1
do
(let ((column-size (length (first column))))
(loop
for row in column
for indices-row-underlined in column-indices
with row-count = 1 do
(let ((text (if (and (= row-count (1+ selected-item-row-index))
(= column-count selected-item-column-index))
(make-tui-string row
:fgcolor foreground-selected-item
:bgcolor background-selected-item)
(make-tui-string row))))
(print-text object
(apply-attributes text
indices-row-underlined
matched-attributes)
column-offset
row-count))
(incf row-count))
(incf column-offset column-size)))
(draw-pagination-info object)))
(win-refresh object))))
(defun init ()

View File

@ -181,13 +181,31 @@ list af all possible candidtae for completion."
(with-simple-complete conversation-folder db:all-conversation-folders)
(defun uri-matcher (scanner bag &optional (accum-strings '()) (accum-indices '()))
(if (null bag)
(values accum-strings accum-indices)
(let ((tested (first bag)))
(multiple-value-bind (start end)
(cl-ppcre:scan scanner tested)
(if start
(uri-matcher scanner
(rest bag)
(push tested accum-strings)
(push (loop for i from start below end collect i)
accum-indices))
(uri-matcher scanner (rest bag) accum-strings accum-indices))))))
(defun make-complete-gemini-iri-fn (prompt)
(lambda (hint)
(when-let ((matched (remove-if-not (contains-clsr hint)
(remove-duplicates (funcall #'db:history-prompt->values
prompt)
:test #'string=))))
(values matched (reduce-to-common-prefix matched)))))
(when-let ((bag (remove-duplicates (funcall #'db:history-prompt->values
prompt)
:test #'string=)))
(multiple-value-bind (matched-strings indices)
(uri-matcher (cl-ppcre:create-scanner hint) bag)
(when matched-strings
(values matched-strings
(reduce-to-common-prefix matched-strings)
indices))))))
(defun complete-chat-message (hint)
(append (username-complete hint)

View File

@ -1113,6 +1113,7 @@
:load-config-file
:external-editor
:gemini-downloading-animation
:suggestion-window-selected-item-colors
:gemini-default-favicon
:directory-symbol
:gemini-fetch-favicon-p
@ -1240,7 +1241,8 @@
:with-notify-errors
:with-print-error-message
:make-tui-char
:make-tui-string))
:make-tui-string
:apply-attributes))
(defpackage :command-line
(:use
@ -1737,7 +1739,10 @@
(:shadowing-import-from :text-utils :split-lines)
(:shadowing-import-from :misc :random-elt :shuffle)
(:export
:+starting-item-index+
:complete-window
:selected-item-row-index
:selected-item-column-index
:init))
(defpackage :keybindings-window

View File

@ -564,6 +564,15 @@
(access-key->user-directive keys))))
value)))
(defun suggestion-window-selected-item-colors ()
(values (access-non-null-conf-value *software-configuration*
+key-suggestions-window+
+key-selected+
+key-background+)
(access-non-null-conf-value *software-configuration*
+key-suggestions-window+
+key-selected+
+key-foreground+)))
(defun gemini-downloading-animation ()
(let ((animation (access-non-null-conf-value *software-configuration*
+key-gemini+

View File

@ -412,6 +412,28 @@ latter has a length equals to `total-size'"))
last-char-bg))))
res))))
(defgeneric apply-attributes (object index attributes))
(defmethod apply-attributes ((object complex-string) (index fixnum) attributes)
(let ((char (elt (complex-char-array object) index)))
(setf (attributes char) attributes)
object))
(defmethod apply-attributes ((object string) (index fixnum) attributes)
(apply-attributes (make-tui-string object) index attributes))
(defmethod apply-attributes ((object string) (index list) attributes)
(apply-attributes (make-tui-string object) index attributes))
(defmethod apply-attributes ((object complex-string) (index list) attributes)
(if (null index)
object
(let ((partial (apply-attributes object (first index) attributes)))
(apply-attributes partial (rest index) attributes))))
(defmethod apply-attributes (object (index null) attributes)
object)
(defmethod remove-corrupting-utf8-chars ((object complex-string))
(setf (complex-char-array object)
(remove-if (lambda (a) (display-corrupting-utf8-p (simple-char a)))