Detect if stdout is a pipe Default page is gopherproject - clic - Clic is an command line interactive client for gopher written in Common LISP
 (HTM) git clone git://bitreich.org/clic/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/clic/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 3cf6014aab1eadb344f1a3c2271caa995cb43554
 (DIR) parent f2fe151427976dd0fa6135c5d313333b31732a47
 (HTM) Author: Solene Rapenne <solene@perso.pw>
       Date:   Thu, 28 Dec 2017 10:59:28 +0100
       
       Detect if stdout is a pipe
       Default page is gopherproject
       
       Diffstat:
         M clic.lisp                           |     104 ++++++++++++++++++++-----------
       
       1 file changed, 67 insertions(+), 37 deletions(-)
       ---
 (DIR) diff --git a/clic.lisp b/clic.lisp
       @@ -10,23 +10,31 @@
        #+sbcl
        (progn
          (load-shared-object #p"./extension.so")
       +  ;; getTerminalHeight
          (declaim (inline getTerminalHeight))
          (sb-alien:define-alien-routine "getTerminalHeight" unsigned-int)
          (defun c-termsize ()
            "return terminal height"
            (sb-alien:with-alien ((res unsigned-int (getTerminalHeight))))))
        
       +
        #+ecl
        (progn
          (ffi:clines "
            #include <sys/ioctl.h>
            #include <limits.h>
       +    #include <unistd.h>
       +    int ttyPredicate() {
       +      return isatty(fileno(stdout)); }
            unsigned int getTerminalHeight()  {
              struct winsize w;
              return ioctl(1,TIOCGWINSZ,&w)<0?UINT_MAX:w.ws_row;}")
          (ffi:def-function
              ("getTerminalHeight" c-termsize)
       -      () :returning :unsigned-int))
       +      () :returning :unsigned-int)
       +  (ffi:def-function
       +      ("ttyPredicate" c-ttyp)
       +      () :returning :int))
        ;;;; END C binding
        
        ;; structure to store links
       @@ -82,6 +90,16 @@
        (add-color 'http   0 33)
        ;;;; END ANSI colors
        
       +;;;; is the output interactive or a pipe ?
       +
       +(defun ttyp()
       +  #+sbcl
       +  (interactive-stream-p *standard-output*)
       +  #+ecl
       +  (if (= 1 (c-ttyp))
       +      t
       +      nil))
       +
        (defun print-with-color(text &optional (color 'white) (line-number nil))
          "Used to display a line with a color"
          (format t "~3A| ~a~a~a~%" (if line-number line-number "") (get-color color) text (get-color 'white)))
       @@ -374,42 +392,52 @@
        
        (defun display-buffer(type)
          "display the buffer"
       -  (let ((rows (- (c-termsize) 1))) ; -1 for command bar
        
       -    ;; we store the user input outside of the loop
       -    ;; so if the user doesn't want to scroll
       -    ;; we break the loop and then execute the command
       -    (let ((input nil))
       +  ;; stdout is a terminal or not ?
       +  (if (ttyp)
       +      ;; yes it is
       +      (let ((rows (- (c-termsize) 1))) ; -1 for command bar
       +
       +        ;; we store the user input outside of the loop
       +        ;; so if the user doesn't want to scroll
       +        ;; we break the loop and then execute the command
       +        (let ((input nil))
       +          (loop for line across *buffer*
       +             counting line into row
       +             do
       +             ;; display lines
       +               (cond
       +                 ((string= "1" type)
       +                  (formatted-output line))
       +                 ((string= "0" type)
       +                  (format t "~a~%" line)))
       +
       +             ;; split and ask to scroll or to type a command
       +               (when (= row rows)
       +                 (setf row 0)
       +                 (format t "~a   press enter or a shell command ~a : "
       +                         (get-color 'cyan)
       +                         (get-color  'white))
       +                 (force-output)
       +                 (let ((first-input (read-char)))
       +                   (when (not (char= #\NewLine first-input))
       +                     (unread-char first-input)
       +                     (let ((input-text (format nil "~a" (read-line nil nil))))
       +                       (setf input input-text)
       +                       (loop-finish))))))
       +
       +          ;; in case of shell command, do it
       +          (if input
       +              (user-input input)
       +              (when (< (length *buffer*) rows)
       +                (dotimes (i (- rows (length *buffer*)))
       +                  (format t "~%"))))))
       +
       +      ;; not interactive
       +      ;; display and quit
              (loop for line across *buffer*
       -         counting line into row
       -         do
       -           ;; display lines
       -           (cond
       -             ((string= "1" type)
       -              (formatted-output line))
       -             ((string= "0" type)
       -              (format t "~a~%" line)))
       -
       -           ;; split and ask to scroll or to type a command
       -           (when (= row rows)
       -             (setf row 0)
       -             (format t "~a   press enter or a shell command ~a : "
       -                     (get-color 'cyan)
       -                     (get-color  'white))
       -             (force-output)
       -             (let ((first-input (read-char)))
       -               (when (not (char= #\NewLine first-input))
       -                 (unread-char first-input)
       -                 (let ((input-text (format nil "~a" (read-line nil nil))))
       -                   (setf input input-text)
       -                   (loop-finish))))))
       -
       -      ;; in case of shell command, do it
       -      (if input
       -          (user-input input)
       -          (when (< (length *buffer*) rows)
       -            (dotimes (i (- rows (length *buffer*)))
       -              (format t "~%")))))))
       +         do
       +           (format t "~a~%" line))))
        
        (defun visit(destination)
          "visit a location"
       @@ -471,12 +499,14 @@
                       ;; url as argument
                       (parse-url argv)
                       ;; default url
       -               (make-location :host "bitreich.org" :port 70 :uri "/" :type "1")))))
       +               (make-location :host "gopherproject.org" :port 70 :uri "/" :type "1")))))
        
            ;; if user want to drop from first page we need
            ;; to look it here
            (when (not (eq 'end (visit destination)))
       -      (when (string= "1" (location-type destination))
       +      ;; we continue to the shell if the type was 1 and we are in a terminal
       +      (when (and (ttyp)
       +                 (string= "1" (location-type destination)))
                (shell)))))
        
        ;; we allow ecl to use a new kind of argument