(hissp.basic.._macro_.prelude) ;; Lissp's class definition syntax is somewhat unlike Python's class ;; definition syntax even though it expresses the same model. Python ;; will nearly never imply a dict from a sequence of uncoupled pairs ;; but this is a common way to express an association list in lisps. ;; It's interesting that `deftype` is a macro around a `type` call in ;; its rarely used form with three arguments. Quoting the ;; member/method (it does not distinguist) and class names for you in ;; the macro makes it read a little bit more like Python than it would ;; if you had to quote them. (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")))))