mirror of
https://codeberg.org/cage/tinmop/
synced 2025-02-08 07:08:39 +01:00
- rewritten rendering of text in message window
i got rid of slot support-text in message-window, so that class does not maintain a state. - changed behaivour of split-line (split-line (format nil "~2%")) ; => ("" "") That is an emtpy line is returned as empty string and not skipped Thanks to people from IRC and cl-ppcre maintainer for help! - [breaking changes] changed 'hooks:*before-prepare-for-rendering-message* with 'hooks:*before-rendering-message-text*.
This commit is contained in:
parent
ddb74a600f
commit
6786d48f6d
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
(in-package :modules)
|
(in-package :modules)
|
||||||
|
|
||||||
(defparameter *rewriting-link-rules* ()
|
(defparameter *rewriting-link-rules* '()
|
||||||
"Before displaying messages that module will rewrites the first
|
"Before displaying messages that module will rewrites the first
|
||||||
element of each item of this list with the second
|
element of each item of this list with the second
|
||||||
|
|
||||||
@ -56,13 +56,28 @@ So the whole list is like: '((\"foo\" \"bar\") (\"old\" \"new\") ...)")
|
|||||||
text
|
text
|
||||||
(cdr mapping)))
|
(cdr mapping)))
|
||||||
|
|
||||||
|
(defun %rewriting-link-rewrite-row (links-mapping)
|
||||||
|
(lambda (row)
|
||||||
|
(let* ((original-type (message-window:line-get-original-object row))
|
||||||
|
(original-string (line-oriented-window:normal-text row))
|
||||||
|
(skipped-row-types (list 'gemini-parser:pre-line
|
||||||
|
'gemini-parser:vertical-space)))
|
||||||
|
(if (member original-type skipped-row-types)
|
||||||
|
row
|
||||||
|
(let* ((simple-string (tui:tui-string->chars-string original-string))
|
||||||
|
(replaced-string simple-string))
|
||||||
|
(loop for mapping in links-mapping do
|
||||||
|
(setf replaced-string
|
||||||
|
(rewriting-link-replace-mapping mapping replaced-string)))
|
||||||
|
replaced-string)))))
|
||||||
|
|
||||||
(defun rewriting-link-message-hook-fn (message-window)
|
(defun rewriting-link-message-hook-fn (message-window)
|
||||||
(with-accessors ((support-text message-window:support-text)) message-window
|
(let* ((map-fn (%rewriting-link-rewrite-row *rewriting-link-rules*))
|
||||||
(let* ((all-links (text-utils:collect-links support-text))
|
(replaced-rows (line-oriented-window:map-rows message-window
|
||||||
(links-mapping (rewriting-link-messages-links-rules all-links)))
|
map-fn))
|
||||||
(loop for mapping in links-mapping do
|
(new-rows (message-window:text->rendered-lines-rows message-window
|
||||||
(setf support-text
|
replaced-rows)))
|
||||||
(rewriting-link-replace-mapping mapping support-text))))))
|
(line-oriented-window:update-all-rows message-window new-rows)))
|
||||||
|
|
||||||
(defun rewriting-link-links-window-hook-fn (all-links)
|
(defun rewriting-link-links-window-hook-fn (all-links)
|
||||||
(let ((links-mapping (rewriting-link-messages-links-rules all-links))
|
(let ((links-mapping (rewriting-link-messages-links-rules all-links))
|
||||||
@ -75,7 +90,7 @@ So the whole list is like: '((\"foo\" \"bar\") (\"old\" \"new\") ...)")
|
|||||||
(push mapped results)))
|
(push mapped results)))
|
||||||
(reverse results)))
|
(reverse results)))
|
||||||
|
|
||||||
(hooks:add-hook 'hooks:*before-prepare-for-rendering-message*
|
(hooks:add-hook 'hooks:*before-rendering-message-text*
|
||||||
#'rewriting-link-message-hook-fn)
|
#'rewriting-link-message-hook-fn)
|
||||||
|
|
||||||
(hooks:add-hook 'hooks:*before-displaying-links-hook*
|
(hooks:add-hook 'hooks:*before-displaying-links-hook*
|
||||||
|
@ -689,7 +689,7 @@
|
|||||||
(when-let* ((metadata (message-window:metadata window))
|
(when-let* ((metadata (message-window:metadata window))
|
||||||
(source (gemini-metadata-source-file metadata))
|
(source (gemini-metadata-source-file metadata))
|
||||||
(last (misc:safe-last-elt (gemini-metadata-history metadata))))
|
(last (misc:safe-last-elt (gemini-metadata-history metadata))))
|
||||||
(setf (message-window:support-text window) source)
|
(message-window:prepare-for-rendering window source)
|
||||||
(draw window)
|
(draw window)
|
||||||
(ui:info-message (format nil (_ "Viewing source of: ~a") last))))
|
(ui:info-message (format nil (_ "Viewing source of: ~a") last))))
|
||||||
|
|
||||||
|
@ -378,6 +378,12 @@
|
|||||||
:group-id group-id
|
:group-id group-id
|
||||||
:alt-text alt-text))
|
:alt-text alt-text))
|
||||||
|
|
||||||
|
(defclass vertical-space ()
|
||||||
|
((size
|
||||||
|
:initform 1
|
||||||
|
:initarg :size
|
||||||
|
:accessor size)))
|
||||||
|
|
||||||
(defun sexp->text-rows (parsed-gemini theme)
|
(defun sexp->text-rows (parsed-gemini theme)
|
||||||
(labels ((header-prefix (prefix header)
|
(labels ((header-prefix (prefix header)
|
||||||
(strcat prefix header))
|
(strcat prefix header))
|
||||||
@ -417,7 +423,7 @@
|
|||||||
(loop for node in parsed-gemini collect
|
(loop for node in parsed-gemini collect
|
||||||
(cond
|
(cond
|
||||||
((null node)
|
((null node)
|
||||||
(format nil "~%"))
|
(make-instance 'vertical-space)) ;(format nil "~%"))
|
||||||
((html-utils:tag= :as-is node)
|
((html-utils:tag= :as-is node)
|
||||||
(let* ((truncated-line (safe-subseq (text-value node) 0 (1- win-width)))
|
(let* ((truncated-line (safe-subseq (text-value node) 0 (1- win-width)))
|
||||||
(fg (preformatted-fg theme))
|
(fg (preformatted-fg theme))
|
||||||
|
@ -73,6 +73,7 @@
|
|||||||
:pre-end
|
:pre-end
|
||||||
:quoted-lines
|
:quoted-lines
|
||||||
:lines
|
:lines
|
||||||
|
:vertical-space
|
||||||
:sexp->text-rows
|
:sexp->text-rows
|
||||||
:sexp->text
|
:sexp->text
|
||||||
:parse-gemini-response-header
|
:parse-gemini-response-header
|
||||||
|
@ -84,7 +84,7 @@ non-nil.")
|
|||||||
"Run this hooks just before closing the database connection and the
|
"Run this hooks just before closing the database connection and the
|
||||||
program")
|
program")
|
||||||
|
|
||||||
(defparameter *before-prepare-for-rendering-message* '()
|
(defparameter *before-rendering-message-text* '()
|
||||||
"Run this hooks before rendering the message on a
|
"Run this hooks before rendering the message on a
|
||||||
message-window (the message window is passed as parameter")
|
message-window (the message window is passed as parameter")
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@
|
|||||||
(:documentation "This class represents a single line in a row-oriented-widget"))
|
(:documentation "This class represents a single line in a row-oriented-widget"))
|
||||||
|
|
||||||
(defmethod print-object ((object line) stream)
|
(defmethod print-object ((object line) stream)
|
||||||
(format stream "line: ~s" (normal-text object)))
|
(format stream "line: ~s" (tui-string->chars-string (normal-text object))))
|
||||||
|
|
||||||
(defclass row-oriented-widget ()
|
(defclass row-oriented-widget ()
|
||||||
((rows
|
((rows
|
||||||
@ -347,6 +347,16 @@ this exact quantity would go beyond the length or rows or zero."
|
|||||||
:end end
|
:end end
|
||||||
:key key))
|
:key key))
|
||||||
|
|
||||||
|
(defun rows->text-rows (window &key (accessor-fn #'normal-text))
|
||||||
|
(let ((*blanks* '(#\Newline)))
|
||||||
|
(map-rows window
|
||||||
|
(lambda (a)
|
||||||
|
(trim-blanks (tui:tui-string->chars-string (funcall accessor-fn a)))))))
|
||||||
|
|
||||||
|
(defun rows->text (window &key (accessor-fn #'normal-text))
|
||||||
|
(join-with-strings (rows->text-rows window :accessor-fn accessor-fn)
|
||||||
|
(format nil "~%")))
|
||||||
|
|
||||||
(defclass simple-line-navigation-window (wrapper-window row-oriented-widget border-window)
|
(defclass simple-line-navigation-window (wrapper-window row-oriented-widget border-window)
|
||||||
((selected-line-bg
|
((selected-line-bg
|
||||||
:initform :blue
|
:initform :blue
|
||||||
|
@ -20,11 +20,7 @@
|
|||||||
row-oriented-widget
|
row-oriented-widget
|
||||||
focus-marked-window
|
focus-marked-window
|
||||||
title-window)
|
title-window)
|
||||||
((support-text
|
((line-position-mark
|
||||||
:initform nil
|
|
||||||
:initarg :support-text
|
|
||||||
:reader support-text)
|
|
||||||
(line-position-mark
|
|
||||||
:initform (make-tui-string "0")
|
:initform (make-tui-string "0")
|
||||||
:initarg :line-position-mark
|
:initarg :line-position-mark
|
||||||
:accessor line-position-mark)
|
:accessor line-position-mark)
|
||||||
@ -50,13 +46,6 @@
|
|||||||
(setf (keybindings window)
|
(setf (keybindings window)
|
||||||
keybindings:*message-keymap*)))
|
keybindings:*message-keymap*)))
|
||||||
|
|
||||||
(defmethod (setf support-text) (new-text (object message-window))
|
|
||||||
(setf (slot-value object 'support-text) new-text)
|
|
||||||
(handler-bind ((conditions:out-of-bounds
|
|
||||||
(lambda (e)
|
|
||||||
(invoke-restart 'ignore-selecting-action e))))
|
|
||||||
(prepare-for-rendering object)))
|
|
||||||
|
|
||||||
(defun refresh-line-mark-config (window)
|
(defun refresh-line-mark-config (window)
|
||||||
(multiple-value-bind (mark-value mark-fg mark-bg)
|
(multiple-value-bind (mark-value mark-fg mark-bg)
|
||||||
(swconf:message-window-line-mark-values)
|
(swconf:message-window-line-mark-values)
|
||||||
@ -86,6 +75,8 @@
|
|||||||
(declare (ignore object dt)))
|
(declare (ignore object dt)))
|
||||||
|
|
||||||
(defun draw-text (window)
|
(defun draw-text (window)
|
||||||
|
(when hooks:*before-rendering-message-text*
|
||||||
|
(hooks:run-hook 'hooks:*before-rendering-message-text* window))
|
||||||
(with-accessors ((row-selected-index row-selected-index)) window
|
(with-accessors ((row-selected-index row-selected-index)) window
|
||||||
(let ((actual-rows (line-oriented-window:rows-safe-subseq window row-selected-index)))
|
(let ((actual-rows (line-oriented-window:rows-safe-subseq window row-selected-index)))
|
||||||
(loop for line in actual-rows
|
(loop for line in actual-rows
|
||||||
@ -119,10 +110,7 @@
|
|||||||
(draw-buffer-line-mark object))
|
(draw-buffer-line-mark object))
|
||||||
(call-next-method)))
|
(call-next-method)))
|
||||||
|
|
||||||
(defgeneric prepare-for-rendering (object &key (jump-to-first-row)))
|
(defgeneric prepare-for-rendering (object text-data &key jump-to-first-row))
|
||||||
|
|
||||||
(defgeneric append-support-text (object text
|
|
||||||
&key prepare-for-rendering jump-to-first-row))
|
|
||||||
|
|
||||||
(defgeneric scroll-down (object &optional amount))
|
(defgeneric scroll-down (object &optional amount))
|
||||||
|
|
||||||
@ -140,12 +128,26 @@
|
|||||||
|
|
||||||
(defgeneric text->rendered-lines-rows (window text))
|
(defgeneric text->rendered-lines-rows (window text))
|
||||||
|
|
||||||
(defun make-render-vspace-row ()
|
(defun line-add-original-object (line original-object)
|
||||||
(make-instance 'line
|
(push original-object
|
||||||
:normal-text (make-tui-string "")))
|
(fields line))
|
||||||
|
(push :original-object
|
||||||
|
(fields line))
|
||||||
|
line)
|
||||||
|
|
||||||
|
(defun line-get-original-object (line)
|
||||||
|
(getf (fields line) :original-object))
|
||||||
|
|
||||||
|
(defun make-render-vspace-row (&optional (original-object
|
||||||
|
(make-instance 'gemini-parser:vertical-space)))
|
||||||
|
(let ((res (make-instance 'line
|
||||||
|
:normal-text (make-tui-string (format nil "~%"))
|
||||||
|
:fields (list :vertical-space 1))))
|
||||||
|
(line-add-original-object res original-object)
|
||||||
|
res)) ; even if line-add-original-object returns the modified line explicit returns for clarity
|
||||||
|
|
||||||
(defun vspace-row-p (row)
|
(defun vspace-row-p (row)
|
||||||
(string-empty-p (normal-text row)))
|
(getf (fields row) :vertical-space))
|
||||||
|
|
||||||
(defun make-invisible-row ()
|
(defun make-invisible-row ()
|
||||||
(make-instance 'line
|
(make-instance 'line
|
||||||
@ -155,6 +157,9 @@
|
|||||||
(defun invisible-row-p (row)
|
(defun invisible-row-p (row)
|
||||||
(getf (fields row) :invisible))
|
(getf (fields row) :invisible))
|
||||||
|
|
||||||
|
(defmethod text->rendered-lines-rows (window (text gemini-parser:vertical-space))
|
||||||
|
(make-render-vspace-row text))
|
||||||
|
|
||||||
(defmethod text->rendered-lines-rows (window (text gemini-parser:pre-start))
|
(defmethod text->rendered-lines-rows (window (text gemini-parser:pre-start))
|
||||||
(make-invisible-row))
|
(make-invisible-row))
|
||||||
|
|
||||||
@ -162,13 +167,14 @@
|
|||||||
(make-invisible-row))
|
(make-invisible-row))
|
||||||
|
|
||||||
(defmethod text->rendered-lines-rows (window (text gemini-parser:pre-line))
|
(defmethod text->rendered-lines-rows (window (text gemini-parser:pre-line))
|
||||||
(make-instance 'line
|
(let ((res (make-instance 'line
|
||||||
:normal-text
|
:normal-text
|
||||||
(reduce #'tui:cat-complex-string
|
(reduce #'tui:cat-complex-string
|
||||||
(text->rendered-lines-rows window (gemini-parser:lines text)))
|
(text->rendered-lines-rows window (gemini-parser:lines text)))
|
||||||
:fields (list :alt-text (gemini-parser:alt-text text)
|
:fields (list :alt-text (gemini-parser:alt-text text)
|
||||||
:group-id (gemini-parser:group-id text)
|
:group-id (gemini-parser:group-id text)))))
|
||||||
:original-object text)))
|
(line-add-original-object res text)
|
||||||
|
res)) ; even if line-add-original-object returns the modified line explicit returns for clarity
|
||||||
|
|
||||||
(defmethod text->rendered-lines-rows (window (text list))
|
(defmethod text->rendered-lines-rows (window (text list))
|
||||||
(flatten (loop for i in text
|
(flatten (loop for i in text
|
||||||
@ -178,26 +184,6 @@
|
|||||||
(defmethod text->rendered-lines-rows (window (text complex-string))
|
(defmethod text->rendered-lines-rows (window (text complex-string))
|
||||||
text)
|
text)
|
||||||
|
|
||||||
(defmethod update-all-rows :around ((object message-window) (new-rows sequence))
|
|
||||||
(let ((new-rows (remove-if #'invisible-row-p new-rows)))
|
|
||||||
(call-next-method object new-rows)))
|
|
||||||
|
|
||||||
(defmethod append-new-rows :around ((object message-window) (new-rows sequence))
|
|
||||||
(let ((new-rows (loop for new-row in new-rows
|
|
||||||
when (not (invisible-row-p new-row))
|
|
||||||
collect
|
|
||||||
new-row)))
|
|
||||||
(call-next-method object new-rows)))
|
|
||||||
|
|
||||||
(defun colorize-lines (lines)
|
|
||||||
(let ((color-re (swconf:color-regexps)))
|
|
||||||
(loop for line in lines
|
|
||||||
collect
|
|
||||||
(let ((res line))
|
|
||||||
(loop for re in color-re do
|
|
||||||
(setf res (colorize-line res re)))
|
|
||||||
(colorized-line->tui-string res)))))
|
|
||||||
|
|
||||||
(defmethod text->rendered-lines-rows (window (text gemini-parser:quoted-lines))
|
(defmethod text->rendered-lines-rows (window (text gemini-parser:quoted-lines))
|
||||||
(let ((colorized-lines (colorize-lines (gemini-parser:lines text))))
|
(let ((colorized-lines (colorize-lines (gemini-parser:lines text))))
|
||||||
(loop for i in colorized-lines
|
(loop for i in colorized-lines
|
||||||
@ -209,46 +195,69 @@
|
|||||||
(labels ((fit-lines (lines)
|
(labels ((fit-lines (lines)
|
||||||
(let ((res ()))
|
(let ((res ()))
|
||||||
(loop for line in lines do
|
(loop for line in lines do
|
||||||
(if (string-empty-p line)
|
(cond
|
||||||
(push nil res)
|
((or (string-empty-p line)
|
||||||
(loop
|
(string= line (format nil "~%")))
|
||||||
for fitted-line
|
(push (make-render-vspace-row) res))
|
||||||
in (flush-left-mono-text (split-words line)
|
(t
|
||||||
(win-width-no-border window))
|
(loop for fitted-line
|
||||||
do
|
in (flush-left-mono-text (split-words line)
|
||||||
(push fitted-line res))))
|
(win-width-no-border window))
|
||||||
|
do
|
||||||
|
(push fitted-line res)))))
|
||||||
(reverse res))))
|
(reverse res))))
|
||||||
(if (string= text (format nil "~%"))
|
(let* ((lines (split-lines text))
|
||||||
(make-render-vspace-row)
|
(fitted-lines (fit-lines lines))
|
||||||
(let* ((lines (split-lines text))
|
(new-rows (colorize-lines fitted-lines)))
|
||||||
(fitted-lines (fit-lines lines))
|
(mapcar (lambda (text-line)
|
||||||
(new-rows (colorize-lines fitted-lines)))
|
(if (typep text-line 'line)
|
||||||
(mapcar (lambda (text-line)
|
text-line
|
||||||
(make-instance 'line
|
(make-instance 'line
|
||||||
:normal-text text-line))
|
:normal-text text-line)))
|
||||||
new-rows)))))
|
new-rows))))
|
||||||
|
|
||||||
(defmethod text->rendered-lines-rows (window (text null))
|
;; (defmethod text->rendered-lines-rows (window (text null))
|
||||||
(make-render-vspace-row))
|
;; (make-render-vspace-row))
|
||||||
|
|
||||||
(defmethod prepare-for-rendering ((object message-window) &key (jump-to-first-row t))
|
(defmethod text->rendered-lines-rows (window (text line))
|
||||||
(with-accessors ((support-text support-text)) object
|
text)
|
||||||
(when hooks:*before-prepare-for-rendering-message*
|
|
||||||
(hooks:run-hook 'hooks:*before-prepare-for-rendering-message* object))
|
|
||||||
(update-all-rows object
|
|
||||||
(text->rendered-lines-rows object support-text))
|
|
||||||
(when jump-to-first-row
|
|
||||||
(select-row object 0))
|
|
||||||
object))
|
|
||||||
|
|
||||||
(defmethod append-support-text ((object message-window) text
|
(defmethod update-all-rows :around ((object message-window) (new-rows sequence))
|
||||||
&key
|
(let ((actual-rows (remove-if #'invisible-row-p new-rows)))
|
||||||
(prepare-for-rendering nil)
|
(call-next-method object actual-rows)))
|
||||||
(jump-to-first-row nil))
|
|
||||||
(with-slots (support-text) object
|
(defmethod append-new-rows :around ((object message-window) (new-rows sequence))
|
||||||
(setf support-text (strcat support-text text))
|
(let ((new-rows (loop for new-row in new-rows
|
||||||
(when prepare-for-rendering
|
when (not (invisible-row-p new-row))
|
||||||
(prepare-for-rendering object :jump-to-first-row jump-to-first-row))))
|
collect
|
||||||
|
new-row)))
|
||||||
|
(call-next-method object new-rows)))
|
||||||
|
|
||||||
|
(defgeneric colorize-lines (object))
|
||||||
|
|
||||||
|
(defmethod colorize-lines ((object line))
|
||||||
|
object)
|
||||||
|
|
||||||
|
(defmethod colorize-lines ((object complex-string))
|
||||||
|
(make-instance 'line :normal-text object))
|
||||||
|
|
||||||
|
(defmethod colorize-lines ((object string))
|
||||||
|
(let ((color-re (swconf:color-regexps))
|
||||||
|
(res object))
|
||||||
|
(loop for re in color-re do
|
||||||
|
(setf res (colorize-line res re)))
|
||||||
|
(colorized-line->tui-string res)))
|
||||||
|
|
||||||
|
(defmethod colorize-lines ((object list))
|
||||||
|
(loop for line in object
|
||||||
|
collect
|
||||||
|
(colorize-lines line)))
|
||||||
|
|
||||||
|
(defmethod prepare-for-rendering ((object message-window) text-data &key (jump-to-first-row t))
|
||||||
|
(update-all-rows object (text->rendered-lines-rows object text-data))
|
||||||
|
(when jump-to-first-row
|
||||||
|
(select-row object 0))
|
||||||
|
object)
|
||||||
|
|
||||||
(defun offset-to-move-end (win)
|
(defun offset-to-move-end (win)
|
||||||
(with-accessors ((rows rows)
|
(with-accessors ((rows rows)
|
||||||
|
@ -348,6 +348,7 @@
|
|||||||
(:export
|
(:export
|
||||||
:+float-regexp+
|
:+float-regexp+
|
||||||
:+integer-regexp+
|
:+integer-regexp+
|
||||||
|
:*blanks*
|
||||||
:uchar-length
|
:uchar-length
|
||||||
:utf8-encoded-p
|
:utf8-encoded-p
|
||||||
:clean-unprintable-chars
|
:clean-unprintable-chars
|
||||||
@ -1201,6 +1202,7 @@
|
|||||||
:combine-attributes
|
:combine-attributes
|
||||||
:colorize-line
|
:colorize-line
|
||||||
:colorized-line->tui-string
|
:colorized-line->tui-string
|
||||||
|
:apply-coloring
|
||||||
:standard-error-notify-life
|
:standard-error-notify-life
|
||||||
:with-notify-errors
|
:with-notify-errors
|
||||||
:with-print-error-message
|
:with-print-error-message
|
||||||
@ -1506,7 +1508,7 @@
|
|||||||
:run-hook-until-success
|
:run-hook-until-success
|
||||||
:*before-main-loop*
|
:*before-main-loop*
|
||||||
:*before-quit*
|
:*before-quit*
|
||||||
:*before-prepare-for-rendering-message*
|
:*before-rendering-message-text*
|
||||||
:*before-sending-message*
|
:*before-sending-message*
|
||||||
:*skip-message-hook*
|
:*skip-message-hook*
|
||||||
:*after-saving-message*
|
:*after-saving-message*
|
||||||
@ -1826,6 +1828,8 @@
|
|||||||
:rows-last-elt
|
:rows-last-elt
|
||||||
:rows-first-elt
|
:rows-first-elt
|
||||||
:rows-position-if
|
:rows-position-if
|
||||||
|
:rows->text-rows
|
||||||
|
:rows->text
|
||||||
:row-move
|
:row-move
|
||||||
:simple-line-navigation-window
|
:simple-line-navigation-window
|
||||||
:selected-line-bg
|
:selected-line-bg
|
||||||
@ -1926,14 +1930,14 @@
|
|||||||
(:shadowing-import-from :misc :random-elt :shuffle)
|
(:shadowing-import-from :misc :random-elt :shuffle)
|
||||||
(:export
|
(:export
|
||||||
:message-window
|
:message-window
|
||||||
:support-text
|
|
||||||
:metadata
|
:metadata
|
||||||
:gemini-window-p
|
:gemini-window-p
|
||||||
:display-gemini-text-p
|
:display-gemini-text-p
|
||||||
:display-chat-p
|
:display-chat-p
|
||||||
|
:line-get-original-object
|
||||||
:text->rendered-lines-rows
|
:text->rendered-lines-rows
|
||||||
:prepare-for-display-status-mode
|
:prepare-for-display-status-mode
|
||||||
:append-support-text
|
:prepare-for-rendering
|
||||||
:scroll-down
|
:scroll-down
|
||||||
:scroll-up
|
:scroll-up
|
||||||
:scroll-end
|
:scroll-end
|
||||||
|
@ -1352,8 +1352,8 @@
|
|||||||
(db:mark-all-chat-messages-read chat-id)
|
(db:mark-all-chat-messages-read chat-id)
|
||||||
(setf (windows:keybindings specials:*message-window*)
|
(setf (windows:keybindings specials:*message-window*)
|
||||||
keybindings:*chat-message-keymap*)
|
keybindings:*chat-message-keymap*)
|
||||||
(setf (message-window:support-text specials:*message-window*)
|
(message-window:prepare-for-rendering specials:*message-window*
|
||||||
(chats-list-window:chat->text chat))
|
(chats-list-window:chat->text chat))
|
||||||
(message-window:scroll-end specials:*message-window*)
|
(message-window:scroll-end specials:*message-window*)
|
||||||
(setf (message-window:metadata specials:*message-window*)
|
(setf (message-window:metadata specials:*message-window*)
|
||||||
chat)
|
chat)
|
||||||
|
@ -143,11 +143,28 @@
|
|||||||
(defun join-with-strings* (junction &rest strings)
|
(defun join-with-strings* (junction &rest strings)
|
||||||
(apply #'join-with-strings strings (list junction)))
|
(apply #'join-with-strings strings (list junction)))
|
||||||
|
|
||||||
|
(defvar *blanks* '(#\Space #\Newline #\Backspace #\Tab
|
||||||
|
#\Linefeed #\Page #\Return #\Rubout))
|
||||||
|
|
||||||
|
(defgeneric trim-blanks (s))
|
||||||
|
|
||||||
|
(defmethod trim-blanks ((s string))
|
||||||
|
(string-trim *blanks* s))
|
||||||
|
|
||||||
|
(defmethod trim-blanks ((s null))
|
||||||
|
s)
|
||||||
|
|
||||||
(defun split-words (text)
|
(defun split-words (text)
|
||||||
(cl-ppcre:split "\\p{White_Space}" text))
|
(cl-ppcre:split "\\p{White_Space}" text))
|
||||||
|
|
||||||
(defun split-lines (text)
|
(defun split-lines (text)
|
||||||
(cl-ppcre:split "[\\n\\r]" text))
|
(let ((res ()))
|
||||||
|
(flex:with-input-from-sequence (stream (babel:string-to-octets text))
|
||||||
|
(loop for line-as-array = (misc:read-line-into-array stream)
|
||||||
|
while line-as-array do
|
||||||
|
(push (babel:octets-to-string line-as-array) res)))
|
||||||
|
(let ((*blanks* '(#\Newline)))
|
||||||
|
(reverse (mapcar #'trim-blanks res)))))
|
||||||
|
|
||||||
(defun min-length-word (text)
|
(defun min-length-word (text)
|
||||||
(loop for i in (split-words text)
|
(loop for i in (split-words text)
|
||||||
@ -237,17 +254,6 @@ Uses `test' to match strings (default #'string=)"
|
|||||||
(length end))
|
(length end))
|
||||||
(funcall test s end :start1 (- (length s) (length end)))))
|
(funcall test s end :start1 (- (length s) (length end)))))
|
||||||
|
|
||||||
(defvar *blanks* '(#\Space #\Newline #\Backspace #\Tab
|
|
||||||
#\Linefeed #\Page #\Return #\Rubout))
|
|
||||||
|
|
||||||
(defgeneric trim-blanks (s))
|
|
||||||
|
|
||||||
(defmethod trim-blanks ((s string))
|
|
||||||
(string-trim *blanks* s))
|
|
||||||
|
|
||||||
(defmethod trim-blanks ((s null))
|
|
||||||
s)
|
|
||||||
|
|
||||||
(defun justify-monospaced-text (text &optional (chars-per-line 30))
|
(defun justify-monospaced-text (text &optional (chars-per-line 30))
|
||||||
(if (null (split-words text))
|
(if (null (split-words text))
|
||||||
(list " ")
|
(list " ")
|
||||||
|
@ -814,11 +814,11 @@ db:renumber-timeline-message-index."
|
|||||||
(actual-attachments (if (string= attachments reblogged-status-attachments)
|
(actual-attachments (if (string= attachments reblogged-status-attachments)
|
||||||
attachments
|
attachments
|
||||||
(strcat reblogged-status-attachments attachments))))
|
(strcat reblogged-status-attachments attachments))))
|
||||||
(setf (message-window:support-text *message-window*)
|
(message-window:prepare-for-rendering *message-window*
|
||||||
(strcat header
|
(strcat header
|
||||||
actual-body
|
actual-body
|
||||||
poll-text
|
poll-text
|
||||||
actual-attachments))
|
actual-attachments))
|
||||||
(db:mark-status-red-p timeline-type timeline-folder status-id)
|
(db:mark-status-red-p timeline-type timeline-folder status-id)
|
||||||
(resync-rows-db object :redraw t)
|
(resync-rows-db object :redraw t)
|
||||||
(program-events:push-event refresh-event)
|
(program-events:push-event refresh-event)
|
||||||
|
@ -369,7 +369,6 @@ latter has a length equals to `total-size'"))
|
|||||||
:fgcolor fgcolor
|
:fgcolor fgcolor
|
||||||
:bgcolor bgcolor))
|
:bgcolor bgcolor))
|
||||||
|
|
||||||
|
|
||||||
(defmethod colorized-line->tui-string ((line complex-string) &key &allow-other-keys)
|
(defmethod colorized-line->tui-string ((line complex-string) &key &allow-other-keys)
|
||||||
line)
|
line)
|
||||||
|
|
||||||
@ -380,6 +379,39 @@ latter has a length equals to `total-size'"))
|
|||||||
line
|
line
|
||||||
:initial-value (make-tui-string "")))
|
:initial-value (make-tui-string "")))
|
||||||
|
|
||||||
|
(defgeneric apply-coloring (from to))
|
||||||
|
|
||||||
|
(defmethod apply-coloring ((from complex-string) (to string))
|
||||||
|
(with-accessors ((complex-char-array-from complex-char-array)) from
|
||||||
|
(let* ((res (make-tui-string to))
|
||||||
|
(length-diff (- (length to)
|
||||||
|
(text-length from)))
|
||||||
|
(last-char-from (last-elt complex-char-array-from))
|
||||||
|
(last-char-fg (fgcolor last-char-from))
|
||||||
|
(last-char-bg (bgcolor last-char-from))
|
||||||
|
(last-char-attr (attributes last-char-from)))
|
||||||
|
(with-accessors ((complex-char-array-to complex-char-array)) res
|
||||||
|
(loop
|
||||||
|
for from-char across complex-char-array-from
|
||||||
|
for to-char across complex-char-array-to
|
||||||
|
do
|
||||||
|
(setf (attributes to-char)
|
||||||
|
(attributes from-char))
|
||||||
|
(setf (fgcolor to-char)
|
||||||
|
(fgcolor from-char))
|
||||||
|
(setf (bgcolor to-char)
|
||||||
|
(bgcolor from-char)))
|
||||||
|
(when (> length-diff 0)
|
||||||
|
(loop for i from length-diff below (length to) do
|
||||||
|
(let ((char (elt complex-char-array-to i)))
|
||||||
|
(setf (attributes char)
|
||||||
|
last-char-attr)
|
||||||
|
(setf (fgcolor char)
|
||||||
|
last-char-fg)
|
||||||
|
(setf (bgcolor char)
|
||||||
|
last-char-bg))))
|
||||||
|
res))))
|
||||||
|
|
||||||
(defgeneric print-debug (object &optional stream))
|
(defgeneric print-debug (object &optional stream))
|
||||||
|
|
||||||
(defmethod print-debug ((object complex-char) &optional (stream *standard-output*))
|
(defmethod print-debug ((object complex-char) &optional (stream *standard-output*))
|
||||||
|
@ -42,7 +42,7 @@
|
|||||||
(temporary-files-count (length fs:*temporary-files-created*)))
|
(temporary-files-count (length fs:*temporary-files-created*)))
|
||||||
(if (> temporary-files-count 0)
|
(if (> temporary-files-count 0)
|
||||||
(progn
|
(progn
|
||||||
(setf (message-window:support-text *message-window*) temporary-text)
|
(message-window:prepare-for-rendering *message-window* temporary-text)
|
||||||
(windows:draw *message-window*)
|
(windows:draw *message-window*)
|
||||||
(ask-string-input #'on-input-complete
|
(ask-string-input #'on-input-complete
|
||||||
:prompt (format nil
|
:prompt (format nil
|
||||||
@ -1876,15 +1876,19 @@ gemini://gemini.circumlunar.space/docs/companion/subscription.gmi
|
|||||||
:payload url)))
|
:payload url)))
|
||||||
(push-event event)))))
|
(push-event event)))))
|
||||||
|
|
||||||
|
(defun send-to-pipe-on-input-complete (command data)
|
||||||
|
(when (and (string-not-empty-p command)
|
||||||
|
data)
|
||||||
|
(push-event (make-instance 'send-to-pipe-event
|
||||||
|
:data data
|
||||||
|
:command command))
|
||||||
|
(info-message (format nil (_ "Command ~s completed") command))))
|
||||||
|
|
||||||
(defun send-to-pipe ()
|
(defun send-to-pipe ()
|
||||||
"Send contents of window to a command"
|
"Send contents of window to a command"
|
||||||
(flet ((on-input-complete (command)
|
(flet ((on-input-complete (command)
|
||||||
(when (string-not-empty-p command)
|
(let ((data (line-oriented-window:rows->text *message-window*)))
|
||||||
(when-let ((data (message-window:support-text *message-window*)))
|
(send-to-pipe-on-input-complete command data))))
|
||||||
(push-event (make-instance 'send-to-pipe-event
|
|
||||||
:data data
|
|
||||||
:command command))
|
|
||||||
(info-message (format nil (_ "Command ~s completed")))))))
|
|
||||||
(ask-string-input #'on-input-complete
|
(ask-string-input #'on-input-complete
|
||||||
:prompt (format nil (_ "Send to command: ")))))
|
:prompt (format nil (_ "Send to command: ")))))
|
||||||
|
|
||||||
@ -1893,10 +1897,6 @@ gemini://gemini.circumlunar.space/docs/companion/subscription.gmi
|
|||||||
(when-let* ((selected-message (line-oriented-window:selected-row-fields *thread-window*))
|
(when-let* ((selected-message (line-oriented-window:selected-row-fields *thread-window*))
|
||||||
(message (db:row-message-rendered-text selected-message)))
|
(message (db:row-message-rendered-text selected-message)))
|
||||||
(flet ((on-input-complete (command)
|
(flet ((on-input-complete (command)
|
||||||
(when (string-not-empty-p command)
|
(send-to-pipe-on-input-complete command message)))
|
||||||
(push-event (make-instance 'send-to-pipe-event
|
|
||||||
:data message
|
|
||||||
:command command))
|
|
||||||
(notify (format nil (_ "Command ~s completed"))))))
|
|
||||||
(ask-string-input #'on-input-complete
|
(ask-string-input #'on-input-complete
|
||||||
:prompt (format nil (_ "Send message to command: "))))))
|
:prompt (format nil (_ "Send message to command: "))))))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user