Files
livesort/livesort_hssp/livesort.lissp
T
2021-04-28 07:14:17 -04:00

78 lines
3.1 KiB
Plaintext

(hissp.basic.._macro_.prelude)
(deftype Livesort ()
__init__
(lambda (self
next-line ; iterable function yielding lines of text
print ; function to write output
height ; window/screen height in lines
width ; window/screen width in characters
)
(attach self next-line print height width :
lines (list) ; sorted input lines
screen (list (mul height '(None))))
None) ; __init__ required to return `None`
sortline
(lambda (self line)
"Insort a line and update the cursor position"
(when (.strip line)
(let (lineno (bisect..bisect self.lines line))
;; Normally would use `..insort` but there's going to be more
(.insert self.lines lineno line))))
render
(lambda (self)
"Produce a list of the lines which should be visible, cropped to `width`"
(list (map (lambda (line) (getitem line (slice None self.width)))
(getitem self.lines (slice None self.height)))))
display
(lambda (self)
"Compare `(self.render)` to `self.screen` and return a string that
will update the display."
(let (output (list)
lines (self.render)
changed? (list))
(.append output "") ; Home cursor
(any-for lineno (range self.height)
(let (line (if-else (lt lineno (len lines))
(getitem lines lineno)
""))
(unless (eq line (getitem self.screen lineno))
(setitem self.screen lineno line)
;; `changed?` might have just been an explicit
;; boolean value, but Hissp would prefer that we
;; mutate values and not reassign variables. Since
;; a `list` is an implicit boolean value, appending
;; (or not) to it works fine.
(.append changed? line)
;; ^[[K to erase any characters that follow on this line
(.append output (.format "{}"
(.rstrip line (chr 0x0a)))))
(.append output (chr 0x0a))) ; Move to beginning of next line
False)
;; If something changed, don't bother outputting the last cursor
;; movement code. If nothing changed, don't bother outputting
;; anything.
(if-else changed?
(.join "" (getitem output (slice None -1)))
"")))
livesort
(lambda (self)
"Process every input line, updating screen each line"
(any-for line self.next-line
(.sortline self line)
(.print self (.display self))
False)))
(when (eq __name__ '__main__)
(.livesort (Livesort sys..stdin
(lambda (data)
(sys..stdout.write data)
(sys..stdout.flush))
(int (|| (os..getenv 'LINES) "24"))
(int (|| (os..getenv 'COLUMNS) "80")))))