78 lines
3.1 KiB
Plaintext
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 "[H") ; 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 "{}[K"
|
|
(.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")))))
|