;; ,load /home/demattia/studium/studienarbeit/scsh-nuit/scheme/nuit-engine.scm ;;************************************************************************* ;;Zustand ;;Die verschiedenen Fenster ;;------------------------ (define bar1) (define bar2) (define bar3) (define command-win) (define result-win) (define shortcuts '("F1:Exit" "Ctrl+b:Switch Buffer" "Ctrl+s:Insert/Select" "Ctrl+u:-/Unselect" "Ctrl+p:History->prev" "Ctrl+n:History->next" "Ctrl+a:First Pos" "Ctrl+e:End")) ;;Zustand des oberen Fensters (Command-Window) ;;--------------------------- ;;Text (define text-command (list "Welcome in the scsh-ncurses-ui!" "")) ;;gibt an, in welcher Zeile der gesamten Command-History man sich befindet (define pos-command 2) ;;in welcher Spalte (define pos-command-col 2) ;;gibt an, in welcher Zeile des Buffers nach Zeilenumbruch man sich befindet. (define pos-command-fin-ln 2) ;;gibt an, in welcher Zeile des Buffers man sich befindet (define command-buffer-pos-y 2) ;;gibt an, an welcher Position des Buffers man sich befindet. (define command-buffer-pos-x 2) ;;Anzahl der Zeilen des Commando-Buffers (define command-lines 0) ;;Anzahl der Spalten des Commando-Buffers (define command-cols 0) ;;befindet sich der cursor am Ende der letzten Zeile des command-wins? (define can-write-command #t) ;;Zustand des unteren Fensters (Result-Window) ;;---------------------------- ;;Text (define text-result (list "Start entering commands.")) ;;gibt an, in welcher Zeile des Result-Buffers man sich befindet (define pos-result 0) ;;in welcher Spalte (define pos-result-col 0) ;;gibt an, in welcher Zeile des Buffers man sich befindet (define result-buffer-pos-y 0) ;;gibt an, an welcher Position des Buffers man sich befindet. (define result-buffer-pos-x 0) ;;Anzahl der Zeilen des Buffers (define result-lines 0) ;;Anzahl der Spalten des Buffers (define result-cols 0) ;;welche Zeilen sollen gehighlighted werden? (define highlighted-lines '()) ;;welche Zeilen sollen markiert werden? (define marked-lines '()) ;;allgemeiner Zustand ;;------------------- ;;entweder 1...oben oder 2...unten (define active-buffer 1) ;;History (define history '()) ;;Position in der History (define history-pos 0) ;;Datentyp f�r History-Eintr�ge (define-record-type history-entry history-entry (make-history-entry command result-object) history-entry? (command history-entry-command) (result-object history-entry-result-object)) ;;aktiver Befehl (define active-command "") ;;actives Result-Objekt (define current-result-object) ;;Typen f�r Nachrichten ;;--------------------- ;;Ein neuer Befehl wurde eingegeben ;;-> neues "Object" erzeugen anhand der Parameter in einer Liste (define-record-type next-command-message next-command-message (make-next-command-message command-string parameters width) next-command-message? (command-string next-command-string) (parameters next-command-message-parameters) (width next-command-message-width)) ;;Es wurde eine Taste gedr�ckt ;;->Es wird das Objekt und die Taste an den "User-Code" weitergegeben ;; und dann kommt das ver�nderte Objekt zur�ck. (define-record-type key-pressed-message key-pressed-message (make-key-pressed-message command-string result-model key) key-pressed-message? (command-string key-pressed-command-string) (result-model key-pressed-message-result-model) (key key-pressed-message-key)) ;;Zeichnen (define-record-type print-message print-message (make-print-message command-string object) print-message? (command-string print-message-command-string) (object print-message-object)) ;;->solch ein Datentyp kommt zur�ck (define-record-type print-object print-object (make-print-object pos-y pos-x text highlighted-lines marked-lines) (pos-y print-object-pos-y) (pos-x print-object-pos-x) (text print-object-text) (highlighted-lines print-object-highlighted-lines) (marked-lines print-object-marked-lines)) ;;Wiederherstellen (bei Seiteneffekten) (define-record-type restore-message restore-message (make-restore-message command-string object) restore-message? (command-string restore-message-command-string) (object restore-message-object)) ;;Auswahl anfordern (define-record-type selection-message selection-message (make-selection-message command-string object) selection-message? (command-string selection-message-command-string) (object selection-message-object)) ;;Der Benutzer muss bei Erweiterungen angeben an welche Funktion die ;;Nachrichten bei einem bestimmten Befehl auszuliefern ist (define-record-type receiver receiver (make-receiver command rec) receiver? (command receiver-command) (rec receiver-rec)) ;;************************************************************************* ;;Verhalten ;;Eingabe verarbeiten (define run (lambda () (begin ;;Initialisierung ;;erfolgt nur am Anfang (init-screen) (set! bar1 (newwin 0 0 0 0)) (set! bar2 (newwin 0 0 0 0)) (set! bar3 (newwin 0 0 0 0)) (set! command-win (newwin 0 0 0 0)) (set! result-win (newwin 0 0 0 0)) ;;Loop (let loop ((ch (paint))) (cond ;;Das Resultat dieser TAstendr�cke ist unabh�ngig vom activen Buffer ;;Beenden ((= ch key-f1) (begin (let ((restore-message (make-restore-message active-command current-result-object))) (switch restore-message)) (endwin))) ;;Ctrl+b -> Buffer wechseln ((= ch 2) (begin (if (= active-buffer 1) (set! active-buffer 2) (set! active-buffer 1)) (loop (paint)))) ;;Erfolgt der TAstendruck bei aktivem Ergebnis-Buffer, so wird eine ;;entsprechende Nachricht versendet. (else (if (= active-buffer 2) (let ((key-message (make-key-pressed-message active-command current-result-object ch))) (begin (set! current-result-object (switch key-message)) (loop (paint)))) (cond ;;Enter ((= ch 10) (begin ;;Es wird die restore-Prozedur aufgerufen ; (let ((restore-message (make-restore-message ; active-command ; current-result-object))) ; (switch restore-message)) (execute-command) (loop (paint)))) ;;Backspace ((= ch key-backspace) (if can-write-command (if (< pos-command-col 3) (loop (paint)) (begin (remove-from-command-buffer) (set! pos-command-col (- pos-command-col 1)) (loop (paint)))) (loop (paint)))) ;;Navigieren ((= ch key-up) (if (< pos-command-fin-ln 2) (loop (paint)) (let ((length-prev-line (string-length (list-ref text-command (- pos-command 2))))) (begin (set! can-write-command #f) (set! pos-command (- pos-command 1)) (set! pos-command-col (+ length-prev-line 2)) (loop (paint)))))) ((= ch key-down) (let ((last-pos (length text-command))) (if (>= pos-command last-pos) (loop (paint)) (let ((length-next-line (string-length (list-ref text-command pos-command)))) (begin (set! pos-command-col (+ length-next-line 2)) (set! pos-command (+ pos-command 1)) (if (= pos-command last-pos) (set! can-write-command #t)) (loop (paint))))))) ((= ch key-left) (if (<= pos-command-col 2) (loop (paint)) (begin (set! pos-command-col (- pos-command-col 1)) (loop (paint))))) ((= ch key-right) (let ((line-length (string-length (list-ref text-command (- pos-command 1))))) (if (>= pos-command-col (+ line-length 2)) (loop (paint)) (begin (set! pos-command-col (+ pos-command-col 1)) (loop (paint)))))) ;;Ctrl+p -> History zur�ck ((= ch 16) (begin (history-back) (loop (paint)))) ;;Ctrl+n -> History vor ((= ch 14) (begin (history-forward) (loop (paint)))) ;;Ctrl+s -> Auswahl-holen ((= ch 19) (let* ((message (make-selection-message active-command current-result-object)) (marked-items (switch message))) (begin (add-string-to-command-buffer marked-items) (loop (paint))))) ;;Ctrl+a -> Zeilenanfang ((= ch 1) (begin (set! pos-command-col 2) (loop (paint)))) ;;Ctrl-e -> Zeilenende ((= ch 5) (let ((line-length (string-length (list-ref text-command (- pos-command 1))))) (begin ;(set! command-buffer-pos-x (+ line-length 2)) (set! pos-command-col (+ line-length 2)) (loop (paint))))) (else (if (<= ch 255) (if can-write-command (begin (add-to-command-buffer ch) (loop (paint))) (loop (paint))) (loop (paint)))))))))))) ;;darstellen und auf Eingabe warten (define paint (lambda () (begin (init-screen) (cbreak) (let* ((bar1-y 0) (bar1-x 0) (bar1-h 3) (bar1-w (COLS)) (bar2-y (round (/ (LINES) 3))) (bar2-x 0) (bar2-h 3) (bar2-w (COLS)) (comwin-y 3) (comwin-x 0) (comwin-h (- bar2-y 3)) (comwin-w (COLS)) (reswin-y (+ bar2-y 3)) (reswin-x 0) (reswin-h (- (- (- (LINES) 6) comwin-h) 4)) (reswin-w (COLS)) (bar3-y (+ reswin-y reswin-h)) (bar3-x 0) (bar3-h 4) (bar3-w (COLS))) (wclear bar1) (wclear bar2) (wclear command-win) (wclear result-win) (wclear bar3) (clear) (set! bar1 (newwin bar1-h bar1-w bar1-y bar1-x)) (set! bar2 (newwin bar2-h bar2-w bar2-y bar2-x)) (set! command-win (newwin comwin-h comwin-w comwin-y comwin-x)) (set! result-win (newwin reswin-h reswin-w reswin-y reswin-x)) (set! bar3 (newwin bar3-h bar3-w bar3-y bar3-x)) (box bar1 (ascii->char 0) (ascii->char 0)) (mvwaddstr bar1 1 1 "Command") (wrefresh bar1) (box bar2 (ascii->char 0) (ascii->char 0)) (mvwaddstr bar2 1 1 "Result") (wrefresh bar2) (box command-win (ascii->char 0) (ascii->char 0)) (set! command-lines (- comwin-h 2)) (set! command-cols (- comwin-w 3)) (print-command-buffer command-win) (wrefresh command-win) (box result-win (ascii->char 0) (ascii->char 0)) (set! result-lines (- reswin-h 2)) (set! result-cols (- reswin-w 3)) (print-result-buffer result-win) (wrefresh result-win) (box bar3 (ascii->char 0) (ascii->char 0)) (wattron bar3 (A-REVERSE)) (print-bar3 (- reswin-w 3)) ;(mvwaddstr bar3 1 1 "F1:Exit | Ctrl+b:Switch-Buffer") (wstandend bar3) (wrefresh bar3) (cursor-right-pos command-win result-win comwin-h reswin-h) (noecho) (keypad bar1 #t) (let ((ch (wgetch bar1))) (echo) ch ))))) ;;Auswerten ;;Eingabe wurde durch Benutzer best�tigt -> Kommando ausfuehren (define execute-command (lambda () (let* ((command (list-ref text-command (- (length text-command) 1))) ;;Hier sollte noch die Behandlung von Parametern eingef�gt werden (message (make-next-command-message command '() result-cols)) (model (switch message))) (begin ;;Vorheriges Objekt in History sichern (if (not (= history-pos 0)) (let ((hist-entry (make-history-entry active-command current-result-object)) (active (make-history-entry command model))) (begin (if (< history-pos (length history)) (set! history (append history (list hist-entry))) (set! history (append (sublist history 0 (- (length history) 1)) (list hist-entry) (list active)))) (set! history-pos (length history)))) ;;Dieser Fall tritt nur ganz am Anfang ein. (let ((hist-entry (make-history-entry command model))) (begin (set! history (list hist-entry)) (set! history-pos 1)))) (set! text-command (append text-command (list ""))) (set! active-command command) (set! current-result-object model) (scroll-command-buffer))))) ;;Nach einer Eingabe kann es sein, dass die aktive Buffer_Zeile verschoben ;;werden muss. (define scroll-command-buffer (lambda () (begin (set! pos-command (+ pos-command 1)) (set! pos-command-col 2)))) ;;Auswerten eines Ausdrucks in Form eines String (define evaluate (lambda (exp) (let* ((command-port (open-input-string exp)) (handler (lambda (condition more) (cons 'Error: condition))) (structure (reify-structure 'scheme-with-scsh)) (s (load-structure structure)) (env (rt-structure->environment structure)) (result (with-fatal-error-handler handler (eval (read command-port) env)))) result))) ;;Nachrichten-Vermittlung ;;Der Switch sorgt daf�r, dass die Nachrichten richtig ankommen (define switch (lambda (message) (let ((command "")) (begin (cond ((next-command-message? message) (set! command (next-command-string message))) ((key-pressed-message? message) (set! command (key-pressed-command-string message))) ((print-message? message) (set! command (print-message-command-string message))) ((restore-message? message) (set! command (restore-message-command-string message))) ((selection-message? message) (set! command (selection-message-command-string message)))) (let ((receiver (get-receiver command))) (if receiver (receiver message) (standard-receiver message))))))) (define get-receiver (lambda (command) (let loop ((recs receivers)) (if (= 0 (length recs)) #f (let* ((act-rec (car recs)) (act-com (receiver-command act-rec)) (act-rec-proc (receiver-rec act-rec))) (if (equal? command act-com) act-rec-proc (loop (cdr recs)))))))) ;;Steuerung der oberen Buffers ;;Ein Character zur letzten Zeile des Command-Buffers hinzuf�gen (define add-to-command-buffer (lambda (ch) (let* ((last-pos (- (length text-command) 1)) (old-last-el (list-ref text-command last-pos)) (old-rest (sublist text-command 0 last-pos)) (before-ch (substring old-last-el 0 (max 0 (- pos-command-col 2)))) (after-ch (substring old-last-el (max 0 (- pos-command-col 2)) (string-length old-last-el))) (new-last-el (string-append before-ch (string (ascii->char ch)) after-ch))) (set! text-command (append old-rest (list new-last-el))) (set! pos-command-col (+ pos-command-col 1))))) ;;Einen ganzen String hinzuf�gen ;;->mehrfacher Aufruf von add-to-command-string (define add-string-to-command-buffer (lambda (string) (let loop ((str string)) (if (equal? str "") values (let ((first-ch (string-ref str 0))) (begin (add-to-command-buffer (char->ascii first-ch)) (loop (substring str 1 (string-length str))))))))) ;;Ein Character aus der letzten Zeile entfernen (backspace) (define remove-from-command-buffer (lambda () (let* ((last-pos (- (length text-command) 1)) (old-last-el (list-ref text-command last-pos)) (old-rest (sublist text-command 0 last-pos)) (before-ch (substring old-last-el 0 (max 0 (- pos-command-col 3)))) (after-ch (if (= pos-command-col (+ (string-length old-last-el) 2)) "" (substring old-last-el (max 0 (- pos-command-col 2)) (string-length old-last-el)))) (new-last-el (if (= pos-command-col (+ (string-length old-last-el) 2)) before-ch (string-append before-ch after-ch)))) (set! text-command (append old-rest (list new-last-el)))))) ;;Es wird der sichtbare Teil der bisherigen Eingaben in den Command- ;;Buffer angezeigt. (define print-command-buffer (lambda (comwin) (let ((lines (get-right-command-lines))) (let loop ((pos 1)) (if (> pos command-lines) values (let ((line (list-ref lines (- pos 1)))) (begin (mvwaddstr comwin pos 1 line) (wrefresh comwin) (loop (+ pos 1))))))))) ;;Es werden die anzuzeigenden Zeilen erzeugt. ;;n�tig, damit auch Befehle �ber mehrere Zeilen m�glich sind: (define get-right-command-lines (lambda () (let* ((all-lines-seperated (all-commands-seperated text-command)) (num-all-lines (length all-lines-seperated))) (if (>= pos-command-fin-ln command-lines) ;;aktive Zeile ist die unterste (sublist all-lines-seperated (- pos-command-fin-ln command-lines) command-lines) (if (<= num-all-lines command-lines) ;;noch keine ganze Seite im Buffer (prepare-lines all-lines-seperated command-lines (- pos-command-fin-ln 1)) ;;scrollen auf der ersten Seite (sublist all-lines-seperated 0 command-lines)))))) ;;alle Statements zerlegen (define all-commands-seperated (lambda (commands) (let loop ((act-pos 1) (new '())) (begin (if (= act-pos pos-command) (let* ((length-new (length new)) (first-el-old (list-ref commands (- act-pos 1))) (seperated-act (seperate-line-com first-el-old command-cols)) (length-act (length seperated-act))) (set! pos-command-fin-ln (+ length-new length-act)))) (if (> act-pos (length commands)) (reverse new) (let* ((first-el-old (list-ref commands (- act-pos 1))) (seperated-fst-el-old (seperate-line-com first-el-old command-cols))) (loop (+ act-pos 1) (append seperated-fst-el-old new)))))))) ;;Ein Statement wird in St�cke zerlegt, so dass dann jedes St�ck in eine ;;Zeile passt. (define seperate-line-com (lambda (line width) (let loop ((new '()) (old line)) (if (> width (string-length old)) (if (= 0 (string-length old)) (if (equal? new '()) (add-prompts '("")) (add-prompts new)) ;new (add-prompts (append (list old) new))) ;(append (list old) new)) (let ((next-line (substring old 0 width)) (rest-old (substring old width (string-length old)))) (loop (cons next-line new) rest-old)))))) ;;> hinzuf�gen (define add-prompts (lambda (l) (let* ((lr (reverse l)) (old-first-el (list-ref lr 0)) (new-first-el (string-append ">" old-first-el)) (old-rest (list-tail lr 1))) (let loop ((old old-rest) (new (list new-first-el))) (if (> (length old) 0) (let* ((old-first-el (list-ref old 0)) (new-first-el (string-append " " old-first-el))) (loop (list-tail old 1) (append new (list new-first-el)))) (reverse new)))))) ;;Es wird in einer Liste der zu druckende Berecih ausgew�hlt: (define prepare-lines (lambda (l height pos) (if (< (length l) height) ;; Liste zu kurz -> ""s hinzuf�gen (let loop ((tmp-list l)) (if (= height (length tmp-list)) tmp-list (loop (append tmp-list (list ""))))) ;; Teilliste holen (if (< pos height) ;;pos nicht ganz unten (sublist l 0 height) ;;standard-Fall (sublist l (- pos height) height))))) ;;Darstellen des unteren Buffers ;;Anzeigen des sichtbaren Teils des Result-Buffers (define print-result-buffer (lambda (reswin) (let* ((print-message (make-print-message active-command current-result-object)) (model (switch print-message)) (text (print-object-text model)) (pos-y (print-object-pos-y model)) (pos-x (print-object-pos-x model)) (highlighted-lns (print-object-highlighted-lines model)) (marked-lns (print-object-marked-lines model))) (begin (set! text-result text) (set! pos-result pos-y) (set! pos-result-col pos-x) (set! highlighted-lines highlighted-lns) (set! marked-lines marked-lns) (right-highlighted-lines) (right-marked-lines) (let ((lines (get-right-result-lines))) (let loop ((pos 1)) (if (> pos result-lines) values (let ((line (list-ref lines (- pos 1)))) (if (and (member pos highlighted-lines) (= active-buffer 2)) (begin (wattron reswin (A-REVERSE)) (mvwaddstr reswin pos 1 line) (wattrset reswin (A-NORMAL)) (wrefresh reswin) (loop (+ pos 1))) (if (member pos marked-lines) (begin (wattron reswin (A-BOLD)) (mvwaddstr reswin pos 1 line) (wattrset reswin (A-NORMAL)) (wrefresh reswin) (loop (+ pos 1))) (begin (mvwaddstr reswin pos 1 line) (wrefresh reswin) (loop (+ pos 1))))))))))))) ;;anzuzeigende Zeilen im Result-Buffer (define get-right-result-lines (lambda () (prepare-lines text-result result-lines pos-result))) ;;Markierte und gehighlightete Zeilen berechnen: (define right-highlighted-lines (lambda () (let loop ((old highlighted-lines) (new '())) (if (equal? '() old) (set! highlighted-lines new) (let ((el (car old))) (if (<= pos-result result-lines) ;;auf der ersten Seite (loop (cdr old) (append new (list el))) (let* ((offset (- pos-result result-lines)) (new-el (- el offset ))) (loop (cdr old) (append new (list new-el)))))))))) (define right-marked-lines (lambda () (let loop ((old marked-lines) (new '())) (if (equal? '() old) (set! marked-lines new) (let ((el (car old))) (if (<= pos-result result-lines) ;;auf der ersten Seite (loop (cdr old) (append new (list el))) (let* ((offset (- pos-result result-lines)) (new-el (- el offset ))) (loop (cdr old) (append new (list new-el)))))))))) ;;Cursor ;;Cursor an die richtige Stelle bewegen: (define cursor-right-pos (lambda (comwin reswin comwin-h reswin-h) (begin (compute-y-x) (if (= active-buffer 1) (begin (wmove comwin command-buffer-pos-y command-buffer-pos-x) (wrefresh comwin)) (begin (wmove reswin result-buffer-pos-y result-buffer-pos-x) (wrefresh reswin)))))) ;;pos-y und pos-x berechnen (define compute-y-x (lambda () (if (= active-buffer 1) (begin ;;zuerst mal y (if (>= pos-command-fin-ln command-lines) ;;unterste Zeile (set! command-buffer-pos-y command-lines) ;;sonst (set! command-buffer-pos-y pos-command-fin-ln)) ;;jetzt x (let ((posx (modulo pos-command-col command-cols))) (set! command-buffer-pos-x posx))) (begin ;;zuerst y (if (>= pos-result result-lines) (set! result-buffer-pos-y result-lines) (set! result-buffer-pos-y pos-result)) (set! result-buffer-pos-x pos-result-col))))) ;;Unterstes Fenster (define print-bar3 (lambda (width) (let loop ((pos 0) (used-width 0) (act-line 1)) (if (>= pos (length shortcuts)) (begin (let* ((num-blanks (+ (- width used-width) 1)) (last-string (make-string num-blanks #\space))) (mvwaddstr bar3 act-line (+ used-width 1) last-string)) (wrefresh bar3)) (let* ((act-string (list-ref shortcuts pos)) (act-length (string-length act-string)) (rest-width (- width used-width))) (if (= act-line 1) (if (<= (+ act-length 3) rest-width) (if (= used-width 0) (begin (mvwaddstr bar3 1 (+ used-width 1) act-string) (loop (+ pos 1) (+ used-width act-length) 1)) (begin (mvwaddstr bar3 1 (+ used-width 1) (string-append " | " act-string)) (loop (+ pos 1) (+ used-width (+ 3 act-length)) 1))) (begin (let* ((num-blanks (+ rest-width 1)) (last-string (make-string num-blanks #\space))) (mvwaddstr bar3 1 (+ used-width 1) last-string)) (loop pos 0 2))) (if (<= (+ act-length 3) rest-width) (if (= used-width 0) (begin (mvwaddstr bar3 2 (+ used-width 1) act-string) (loop (+ pos 1) (+ used-width act-length) 2)) (begin (mvwaddstr bar3 2 (+ used-width 1) (string-append " | " act-string)) (loop (+ pos 1) (+ used-width (+ 3 act-length)) 2))) (begin (let* ((num-blanks (+ rest-width 1) ) (last-string (make-string num-blanks #\space))) (mvwaddstr bar3 2 (+ used-width 1) last-string)) (wrefresh bar3))))))))) ;; Ein Schritt zur�ck in der History. Im unteren Buffer wird jeweils das ;; Ergebnis angezeigt (define history-back (lambda () (if (<= history-pos 0) values (let* ((hist-entry (list-ref history (- history-pos 1))) (entry-com (history-entry-command hist-entry)) (entry-res-obj (history-entry-result-object hist-entry))) (begin (set! active-command entry-com) (set! current-result-object entry-res-obj) (set! text-command (append (sublist text-command 0 (- (length text-command) 1)) (list entry-com))) (if (> history-pos 1) (set! history-pos (- history-pos 1)))))))) ;;Ein Schritt nach vorne in der History. Analog zu history-back (define history-forward (lambda () (if (= history-pos (length history) ) (set! text-command (append (sublist text-command 0 (- (length text-command) 1)) (list ""))) (if (> history-pos (- (length history) 1)) values (let* ((hist-entry (list-ref history history-pos)) (entry-com (history-entry-command hist-entry)) (entry-res-obj (history-entry-result-object hist-entry))) (begin (set! text-command (append (sublist text-command 0 (- (length text-command) 1)) (list entry-com))) (set! active-command entry-com) (set! current-result-object entry-res-obj) (set! history-pos (+ history-pos 1)))))))) ;;Teilliste (define sublist (lambda (l pos k) (let ((tmp (list-tail l pos))) (reverse (list-tail (reverse tmp) (- (length tmp) k)))))) ;;************************************************************************* ;;Die folgenden Funktionen sollten sp�ter in eine eigene Datei kommen. ;;Sie sind abh�ngig vom jeweiligen Befehl. ;;Standardfall ;;------------ ;;Datentyp, der das Resultat einer "Standard-Auswertung" repr�sentiert (define-record-type standard-result-obj standard-result-obj (make-standard-result-obj cursor-pos-y cursor-pos-x result-text) standard-result-obj? (cursor-pos-y standard-result-obj-cur-pos-y) (cursor-pos-x standard-result-obj-cur-pos-x) (result-text standard-result-obj-result-text)) (define init-std-res (make-standard-result-obj 1 1 text-result)) (set! current-result-object init-std-res) ;;Standard-Receiver: (define standard-receiver (lambda (message) (cond ((next-command-message? message) (let* ((command (next-command-string message)) (result (evaluate command)) (result-string (exp->string result)) (width (next-command-message-width message))) (let* ((text (layout-result-standard result-string result width)) (std-obj (make-standard-result-obj 1 1 text))) std-obj))) ((print-message? message) (let* ((model (print-message-object message)) (pos-y (standard-result-obj-cur-pos-y model)) (pos-x (standard-result-obj-cur-pos-x model)) (text (standard-result-obj-result-text model))) (make-print-object pos-y pos-x text '() '()))) ((key-pressed-message? message) (key-pressed-message-result-model message)) ((restore-message? message) values) ((selection-message? message) "")))) ;;Im Standardfall wird einfach als Ergebnis die R�ckgabe der scsh ausgegeben. (define layout-result-standard (lambda (result-str result width) (reverse (seperate-line result-str width)))) ;;directory-files ;;--------------- (define initial-working-directory (cwd)) ;;Result-Object f�r "directory-files" (define-record-type dirfiles-result-object dirfiles-result-object (make-dirfiles-result-object pos-y pos-x file-list result-text working-directory width initial-wd marked-items res-marked-items) dirfiles-result-object? (pos-y dirfiles-result-object-pos-y) (pos-x dirfiles-result-object-pos-x) (file-list dirfiles-result-object-file-list) (result-text dirfiles-result-object-result-text) (working-directory dirfiles-result-object-working-directory) (width dirfiles-result-object-width) (initial-wd dirfiles-result-object-initial-wd) (marked-items dirfiles-result-object-marked-items) (res-marked-items dirfiles-result-object-res-marked-items)) ;;Darstellung, falls die Eingabe ist: "(directory-files)" (define layout-result-dirfiles (lambda (result-str result width) (begin (let ((printed-file-list (print-file-list result)) (directory (cwd)) (heading "")) (begin (if (<= (string-length directory) (- width 27)) (set! heading (string-append "Directory-Content of " directory " :")) (let ((dir-string (substring directory (- (string-length directory) (- width 27)) (string-length directory)))) (set! heading (string-append "Directory-Content of ..." dir-string)))) (append (list heading) (list " <-") printed-file-list)))))) ;;Eine Datei pro Zeile ;;Falls es sich um ein Verzeichnis handelt wird "/" hinzugef�gt (define print-file-list (lambda (file-list) (let loop ((old file-list) (new '())) (if (equal? '() old) new (let ((hd (list-ref old 0)) (tl (cdr old))) (if (file-directory? hd) (let ((new-str (string-append " " hd "/"))) (loop tl (append new (list new-str)))) (loop tl (append new (list (string-append " " hd)))))))))) ;;Auswahl->absteigen (define selected-dirfiles (lambda (model) (let ((ln (dirfiles-result-object-pos-y model))) (if (or (>= ln (+ (length (dirfiles-result-object-result-text model)) 1)) (<= ln 1)) model (if (= ln 2) (if (not (equal? "/" (cwd))) (begin (chdir "..") (let* ((new-result (evaluate "(directory-files)")) (new-result-string (exp->string new-result)) (width (dirfiles-result-object-width model)) (new-text (layout-result-dirfiles new-result-string new-result width)) (new-model (make-dirfiles-result-object 2 1 new-result new-text (cwd) width (dirfiles-result-object-initial-wd model) (dirfiles-result-object-marked-items model) (dirfiles-result-object-res-marked-items model)))) new-model)) model) (let* ((text (dirfiles-result-object-result-text model)) (ent (list-ref text (- ln 1))) (len (string-length ent)) (last-char (substring ent (- len 1) len)) (rest (substring ent 1 (- len 1)))) (if (equal? last-char "/") (begin (chdir rest) (let* ((new-result (evaluate "(directory-files)")) (new-result-string (exp->string new-result)) (width (dirfiles-result-object-width model)) (new-text (layout-result-dirfiles new-result-string new-result width)) (new-model (make-dirfiles-result-object 2 1 new-result new-text (cwd) width (dirfiles-result-object-initial-wd model) (dirfiles-result-object-marked-items model) (dirfiles-result-object-res-marked-items model)))) new-model)) model))))))) ;;Receiver f�r directory-files (define dir-files-receiver (lambda (message) (cond ((next-command-message? message) (let* ((command (next-command-string message)) (result (evaluate command)) (result-string (exp->string result)) (width (next-command-message-width message)) (text (layout-result-dirfiles result-string result width)) (model (make-dirfiles-result-object 2 1 result text (cwd) width (cwd) '() '()))) model)) ((print-message? message) (let* ((model (print-message-object message)) (posy (dirfiles-result-object-pos-y model)) (posx (dirfiles-result-object-pos-x model)) (text (dirfiles-result-object-result-text model)) (marked-pos (get-marked-positions (dirfiles-result-object-file-list model) (dirfiles-result-object-marked-items model)))) (make-print-object posy posx text (list posy) marked-pos))) ((key-pressed-message? message) (let* ((model (key-pressed-message-result-model message)) (key (key-pressed-message-key message))) (cond ((= key key-up) (let ((posy (dirfiles-result-object-pos-y model))) (if (<= posy 2) model (let* ((new-posy (- posy 1)) (new-model (make-dirfiles-result-object new-posy (dirfiles-result-object-pos-x model) (dirfiles-result-object-file-list model) (dirfiles-result-object-result-text model) (dirfiles-result-object-working-directory model) (dirfiles-result-object-width model) (dirfiles-result-object-initial-wd model) (dirfiles-result-object-marked-items model) (dirfiles-result-object-res-marked-items model)))) new-model)))) ((= key key-down) (let ((posy (dirfiles-result-object-pos-y model)) (num-lines (length (dirfiles-result-object-result-text model)))) (if (>= posy num-lines) model (let* ((new-posy (+ posy 1)) (new-model (make-dirfiles-result-object new-posy (dirfiles-result-object-pos-x model) (dirfiles-result-object-file-list model) (dirfiles-result-object-result-text model) (dirfiles-result-object-working-directory model) (dirfiles-result-object-width model) (dirfiles-result-object-initial-wd model) (dirfiles-result-object-marked-items model) (dirfiles-result-object-res-marked-items model)))) new-model)))) ((= key 10) (selected-dirfiles model)) ;;Ctrl+s -> Auswahl ((= key 19) (let* ((marked-items (dirfiles-result-object-marked-items model)) (res-marked-items (dirfiles-result-object-res-marked-items model)) (actual-pos (dirfiles-result-object-pos-y model)) (all-items (dirfiles-result-object-file-list model))) (if (<= actual-pos 2) model (let* ((actual-item (list-ref all-items (- actual-pos 3))) (actual-res-item (string-append (cwd) "/" actual-item))) (if (member actual-res-item marked-items) model (let* ((new-res-marked-items (append res-marked-items (list actual-res-item))) (new-marked-items (append marked-items (list actual-item))) (new-model (make-dirfiles-result-object (dirfiles-result-object-pos-y model) (dirfiles-result-object-pos-x model) (dirfiles-result-object-file-list model) (dirfiles-result-object-result-text model) (dirfiles-result-object-working-directory model) (dirfiles-result-object-width model) (dirfiles-result-object-initial-wd model) new-marked-items new-res-marked-items))) new-model)))))) ;;Ctrl+u -> aus Auswahl rausnehmen ((= key 21) (let* ((marked-items (dirfiles-result-object-marked-items model)) (res-marked-items (dirfiles-result-object-res-marked-items model)) (actual-pos (dirfiles-result-object-pos-y model)) (all-items (dirfiles-result-object-file-list model))) (if (<= actual-pos 2) model (let* ((actual-item (list-ref all-items (- actual-pos 3))) (actual-res-item (string-append (cwd) "/" actual-item)) (rest (member actual-item marked-items)) (res-rest (member actual-res-item res-marked-items))) (if (not res-rest) model (let* ((after-item (length rest)) (all-items (length marked-items)) (before-item (sublist marked-items 0 (- all-items after-item ))) (new-marked-items (append before-item (list-tail rest 1))) (after-res-item (length res-rest)) (all-res-items (length res-marked-items)) (before-res-item (sublist res-marked-items 0 (- all-res-items after-res-item))) (new-res-marked-items (append before-res-item (list-tail res-rest 1))) (new-model (make-dirfiles-result-object (dirfiles-result-object-pos-y model) (dirfiles-result-object-pos-x model) (dirfiles-result-object-file-list model) (dirfiles-result-object-result-text model) (dirfiles-result-object-working-directory model) (dirfiles-result-object-width model) (dirfiles-result-object-initial-wd model) new-marked-items new-res-marked-items))) new-model)))))) (else model)))) ((restore-message? message) ;(let ((model (restore-message-object message))) ;(chdir (dirfiles-result-object-initial-wd model)))) (chdir initial-working-directory)) ((selection-message? message) (let* ((model (selection-message-object message)) (marked-items (dirfiles-result-object-res-marked-items model))) (string-append "'" (exp->string marked-items)))) (else values)))) (define dir-files-rec (make-receiver "(directory-files)" dir-files-receiver)) (define receivers (cons dir-files-rec '())) ;;n�tzliche Hilfsfunktionen: (define get-marked-positions (lambda (all-items marked-items) (let loop ((count 0) (result '())) (if (>= count (length all-items)) result (let ((act-item (list-ref all-items count))) (if (member act-item marked-items) (loop (+ count 1) (append result (list (+ count 3)))) (loop (+ count 1) result))))))) ;;Ein Ausdruck als String (define exp->string (lambda (exp) (let ((exp-port (open-output-string))) (begin (write exp exp-port) (get-output-string exp-port))))) ;;Ein Statement wird in St�cke zerlegt, so dass dann jedes St�ck in eine ;;Zeile passt. (define seperate-line (lambda (line width) (let loop ((new '()) (old line)) (if (> width (string-length old)) (if (= 0 (string-length old)) (if (equal? new '()) '("") new) ;new (append (list old) new)) ;(append (list old) new)) (let ((next-line (substring old 0 width)) (rest-old (substring old width (string-length old)))) (loop (cons next-line new) rest-old)))))) ; (define (with-fatal-error-handler* handler thunk) ; (call-with-current-continuation ; (lambda (accept) ; ((call-with-current-continuation ; (lambda (k) ; (with-handler (lambda (condition more) ; (if (error? condition) ; (call-with-current-continuation ; (lambda (decline) ; (k (lambda () (handler condition decline)))))) ; (more)) ; Keep looking for a handler. ; (lambda () (call-with-values thunk accept))))))))) ; (define-syntax with-fatal-error-handler ; (syntax-rules () ; ((with-fatal-error-handler handler body ...) ; (with-fatal-error-handler* handler ; (lambda () body ...))))) ; (run)