Files
livesort/livesort_hy/livesort.hy
T
2021-04-27 12:56:49 -04:00

59 lines
2.2 KiB
Hy

(import [bisect [bisect]])
(defclass Livesort []
(defn __init__ [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
]
(setv self.next-line next-line
self.print print
self.height height
self.width width
self.lines (list)
self.screen (* height [None])))
(defn sortline [self line]
"Insort a line"
(when (line.strip)
;; Normally would use `insort` but there's going to be more
(self.lines.insert (bisect self.lines line) line)))
(defn render [self]
"Produce a list of the lines which should be visible, cropped to `width`"
(list (map (fn [line] (cut line 0 self.width))
(cut self.lines 0 self.height))))
(defn display [self]
"Compare `(self.render)` to `self.screen` and return a string that
will update the display."
(setv output (list)
lines (self.render)
changed? False)
(output.append "") ; Home cursor
(for [lineno (range self.height)]
(setv line (if (< lineno (len lines)) (get lines lineno) ""))
(unless (= line (get self.screen lineno))
(setv (get self.screen lineno) line
changed? True)
;; ^[[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
;; if something changed, don't bother outputting the last cursor
;; movement code. If nothing changed, don't bother outputting
;; anything.
(if changed? (.join "" (cut output 0 -1)) ""))
(defn livesort [self]
"Process every input line, updating screen each line"
(for [line self.next-line]
(.sortline self line)
(.print self (.display self)))))
(defmain
()
(import sys os)
(.livesort
(Livesort sys.stdin
(fn [data] (sys.stdout.write data) (sys.stdout.flush))
(int (or (os.getenv "LINES") "24"))
(int (or (os.getenv "COLUMNS") "80")))))