home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / Programming / Source / winterp-1.13 / examples / grep-br1.0.lsp < prev    next >
Encoding:
Lisp/Scheme  |  1991-10-06  |  13.3 KB  |  420 lines

  1. ; -*-Lisp-*-
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;
  4. ; File:         grep-br1.0.lsp
  5. ; RCS:          $Header: grep-br1.0.lsp,v 1.2 91/10/05 17:13:36 mayer Exp $
  6. ; Description:  Old version of grep-br.lsp, for Motif 1.0. Motif 1.1 users
  7. ;        should use grep-br.lsp. This file is loaded from grep-br.lsp
  8. ; Author:       Niels Mayer, HPLabs
  9. ; Created:      Mon Nov 20 18:13:23 1989
  10. ; Modified:     Sat Oct  5 17:13:16 1991 (Niels Mayer) mayer@hplnpm
  11. ; Language:     Lisp
  12. ; Package:      N/A
  13. ; Status:       X11r5 contrib tape release
  14. ;
  15. ; WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  16. ; XLISP version 2.1, Copyright (c) 1989, by David Betz.
  17. ;
  18. ; Permission to use, copy, modify, distribute, and sell this software and its
  19. ; documentation for any purpose is hereby granted without fee, provided that
  20. ; the above copyright notice appear in all copies and that both that
  21. ; copyright notice and this permission notice appear in supporting
  22. ; documentation, and that the name of Hewlett-Packard and Niels Mayer not be
  23. ; used in advertising or publicity pertaining to distribution of the software
  24. ; without specific, written prior permission.  Hewlett-Packard and Niels Mayer
  25. ; makes no representations about the suitability of this software for any
  26. ; purpose.  It is provided "as is" without express or implied warranty.
  27. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  28.  
  29. ;;
  30. ;; Make a subclass of XM_LIST_WIDGET_CLASS which holds an additional
  31. ;; instance variable 'items'. 'items' is an array of arbitrary objects
  32. ;; (BROWSER_OBJECT) to be displayed in a browser made from the list widget.
  33. ;;
  34. ;; BROWSER-OBJECT can be any arbitrary xlisp object that responds to
  35. ;; the message :display_string.
  36. ;;
  37. ;; Message :display_string must return a string which is used as the
  38. ;; textual representation of the object in the browser display.
  39. ;;
  40. (setq List_Browser_Widget_Class 
  41.       (send Class :new
  42.         '(items)            ;new instance vars
  43.         '()                ;no class vars
  44.         XM_LIST_WIDGET_CLASS))    ;superclass
  45.  
  46. ;;
  47. ;; We add a method to set the items browsed by the list browser
  48. ;; and set the 'items' instance variable.
  49. ;;
  50. ;; (send <List_Browser_Widget_Class_inst> :set_browser_items <items_list>)
  51. ;; <items_list> is a list of BROWSER_OBJECTs as described above.
  52. ;;
  53. (send List_Browser_Widget_Class :answer :SET_BROWSER_ITEMS '(items_list)
  54.       '(
  55.     (let* (
  56.            (items_end_idx (length items_list))
  57.            (display_items (make-array items_end_idx)))
  58.  
  59.       ;; initialize the 'items' instance variable so that it
  60.       ;; holds all the BROWSER_OBJECTs passed in <items_list>
  61.       (setq items (make-array items_end_idx)) ;create the array
  62.       (do (                ;copy elts from list to array
  63.            (i    0          (1+ i))
  64.            (elts items_list (cdr elts)))
  65.           ;; loop till no more elts
  66.           ((null elts))
  67.           ;; loop body
  68.           (setf (aref items i) (car elts))
  69.           (setf (aref display_items i) (send (car elts) :display_string))
  70.           )
  71.       ;; initialize the widget, passing in the browser items.
  72.       (send self :set_values
  73.         :xmn_items display_items
  74.         :xmn_item_count items_end_idx
  75.         )
  76.       )
  77.     )
  78.       )
  79.  
  80.  
  81. ;;
  82. ;; Given a List Widget position, this returns the object associated
  83. ;; with that position. Note that the first item is at position 1.
  84. ;;
  85. (send List_Browser_Widget_Class :answer :GET_ITEM_AT_POSITION '(position)
  86.       '(
  87.     (aref items (1- position))
  88.     ))
  89.  
  90. ;;
  91. ;; override methods on XM_LIST_WIDGET_CLASS so that they work properly
  92. ;; with the list browser. Note that all other list methods work fine
  93. ;; on the list browser
  94. ;;
  95. (send List_Browser_Widget_Class :answer :ADD_ITEM '(item position)
  96.       '(
  97.     (setq items (array-insert-pos items (1- position) item))
  98.     (send-super :add_item (send item :display_string) position)
  99.     )
  100.       )
  101.  
  102. (send List_Browser_Widget_Class :answer :ADD_ITEM_UNSELECTED '(item position)
  103.       '(
  104.     (setq items (array-insert-pos items (1- position) item))
  105.     (send-super :add_item_unselected (send item :display_string) position)
  106.     )
  107.       )
  108.  
  109. (send List_Browser_Widget_Class :answer :DELETE_ITEM '(item)
  110.       '(
  111.     ;; this is too lame to implement... requires that we compare
  112.     ;; item with the result of :display_string done on every element
  113.     ;; of ivar 'items'
  114.     (error "Message :DELETE_ITEM not supported in List_Browser_Widget_Class")
  115.     )
  116.       )
  117.  
  118. (send List_Browser_Widget_Class :answer :DELETE_POS '(position)
  119.       '(
  120.     (setq items (array-delete-pos items (1- position)))
  121.     (send-super :delete_pos position)
  122.     )
  123.       )
  124.  
  125.  
  126. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  127. ;; Define a BROWSER_OBJECT
  128. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  129. ;;
  130. ;; Each BROWSER_OBJECT holds the information summarizing one mail message.
  131. ;; the information is split up into individual fields because we may want
  132. ;; to be able to sort on one field, or search for mathes on one field.
  133. ;;
  134. (setq Grep_Item_Class
  135.       (send Class :new
  136.         '(file-name line-num match-line)
  137.         ))
  138.  
  139. ;; this method will read a single line of grep output.
  140. ;; and sets the instance variables in the 
  141. ;; BROWSER_OBJECT to the individual fields of the grep output
  142. (send Grep_Item_Class :answer :read-grep-info '(pipe)
  143.       '(
  144.     (if (and
  145.          (setq file-name (fscanf-string pipe "%[^:]:"))
  146.          (setq line-num  (fscanf-fixnum pipe "%d:"))
  147.          (setq match-line (fscanf-string pipe "%[^\n]\n"))
  148.          )
  149.         self            ;return self if succesful
  150.       NIL                ;return NIL if hit EOF
  151.       )
  152.     )
  153.       )
  154.  
  155. (send Grep_Item_Class :answer :display_string '()
  156.       '(
  157.     (format nil "~A: ~A"
  158.         file-name match-line)
  159.     ))
  160.  
  161.  
  162. (send Grep_Item_Class :answer :file-name '()
  163.       '(
  164.     file-name
  165.     ))
  166.  
  167. (send Grep_Item_Class :answer :line-num '()
  168.       '(
  169.     line-num
  170.     ))
  171.  
  172. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  173. ;;
  174. ;; This returns a list of Grep_Item_Class instances corresponding
  175. ;; to the items matching the search pattern and file list given
  176. ;; in argument <grep-arg-string>
  177. ;;
  178. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  179. (defun grep (grep-arg-string)
  180.   (do* 
  181.    (;; loop variables, initializers, and increments.
  182.     (fp (popen (strcat "grep -n " grep-arg-string " /dev/null")
  183.            :direction :input))
  184.     (line (send (send Grep_Item_Class :new) :read-grep-info fp)
  185.       (send (send Grep_Item_Class :new) :read-grep-info fp))
  186.     (result '())            ;init to an empty list
  187.     )
  188.    ;; loop test and return
  189.    ((null line)                ; :read-grep-info returns NIL on EOF
  190.     (pclose fp)                ;close the pipe opened above
  191.     (reverse result)            ;return list of grep objects.
  192.     )
  193.    ;; loop body
  194.    (setq result (cons line result))    ;prepend grep-obj to list
  195.    )
  196.   )
  197.  
  198.  
  199. ;;
  200. ;; Make a subclass of XM_TEXT_WIDGET_CLASS which holds an additional
  201. ;; instance variable 'file-path'. 'file-path' is a string representing
  202. ;; the full name of the file in the text editor widget.
  203. ;;
  204. ;; Method :FIND_FILE uses this filename to decide whether it must
  205. ;; read the file into the text widget, or whether it's already 
  206. ;; there. We don't want it to reread uncecessarily since for large
  207. ;; files, this can be slow...
  208. ;;
  209. (setq Text_Viewer_Widget_Class
  210.       (send Class :new
  211.         '(file-path)        ;new instance vars
  212.         '()                ;no class vars
  213.         XM_TEXT_WIDGET_CLASS))    ;superclass
  214.  
  215. ;;
  216. ;; Override superclass's instance initializer so we can set
  217. ;; instance variable, and supply some default arguments.
  218. ;;
  219. (send Text_Viewer_Widget_Class :answer :isnew
  220.       '(managed_k widget_name widget_parent &rest args)
  221.       '(
  222.     (setq file-path "")        ;initialize instance var
  223.     (apply 'send-super        ;call superclass's init to create widget
  224.            `(:isnew ,managed_k :scrolled ,widget_name ,widget_parent
  225.             ,@args
  226.             :XMN_EDIT_MODE :MULTI_LINE_EDIT
  227.             :XMN_EDITABLE  nil ;don't allow user to change text.
  228.             ))
  229.     ))
  230.  
  231. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  232. ;; Add a :FIND_FILE method to the Motif Text widget.
  233. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  234. (send Text_Viewer_Widget_Class :answer :FIND_FILE '(filename linenum)
  235.       '(
  236.     (cond
  237.      ((string= filename file-path)            ;if the file was already read into widget
  238.       (send self :set_insertion_position 0)    ;then just make <linenum> be top
  239.       (send self :scroll (1- linenum))      ;scroll to current line num
  240.       )
  241.      (t                        ;else read the file into the widget...
  242.       (let*
  243.           (;; loc vars
  244.            (fp
  245.         (open filename :direction :input)
  246.         )
  247.            inspos
  248.            text_line
  249.            )
  250.  
  251.         (if (null fp)
  252.         (error "Can't open file." filename))
  253.  
  254.         (send self :set_string "")    ;clear out old text
  255.         (send self :disable_redisplay NIL) ;don't show changes till done
  256.         (loop
  257.          (if (null (setq text_line (read-line fp)))
  258.          (return))
  259.          (setq inspos (send self :get_insertion_position))
  260.          (send self :replace inspos inspos (strcat text_line "\n"))
  261.          )
  262.  
  263.         (send self :scroll linenum)    ;make <linenum> be the top of screen
  264.  
  265.         (send self :enable_redisplay) ;now show changes...
  266.  
  267.         (close fp)
  268.         (setq file-path filename)
  269.         )
  270.       )
  271.      )
  272.     ))
  273.  
  274. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  275. ;; The Main program -- note that this doesn't use any global variables, so
  276. ;; you can have many grep browsers up all at once without having them
  277. ;; interact.
  278. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  279. (defun grep-browser()
  280.  
  281.   (let (
  282.     top_w paned_w controlpanel_w doit_button_w search_label_w
  283.     search_editor_w files_label_w files_editor_w list_w filename_label_w
  284.     viewtext_w
  285.     )
  286.  
  287.     (setq top_w
  288.       (send TOP_LEVEL_SHELL_WIDGET_CLASS :new 
  289.         :XMN_TITLE "Grep Browser"
  290.         :XMN_ICON_NAME "Grep Browser"
  291.         ))
  292.  
  293.     (setq paned_w
  294.       (send XM_PANED_WINDOW_WIDGET_CLASS :new :managed top_w
  295.         ))
  296.  
  297.     (setq controlpanel_w
  298.       (send XM_ROW_COLUMN_WIDGET_CLASS :new :managed paned_w
  299.         :XMN_ADJUST_LAST t
  300.         :XMN_ORIENTATION :HORIZONTAL
  301.         :XMN_PACKING :PACK_TIGHT
  302.         :XMN_NUM_COLUMNS 1
  303.         ))
  304.  
  305.     (setq doit_button_w
  306.       (send XM_PUSH_BUTTON_WIDGET_CLASS :new :managed controlpanel_w
  307.         :XMN_LABEL_STRING "DO SEARCH"
  308.         ))
  309.  
  310.     (setq search_label_w
  311.       (send XM_LABEL_WIDGET_CLASS :new :managed controlpanel_w
  312.         :XMN_LABEL_STRING "Search for string:"
  313.         ))
  314.  
  315.     (setq search_editor_w
  316.       (send XM_TEXT_WIDGET_CLASS :new :managed controlpanel_w
  317.         :XMN_EDIT_MODE :SINGLE_LINE_EDIT))
  318.  
  319.     (setq files_label_w
  320.       (send XM_LABEL_WIDGET_CLASS :new :managed controlpanel_w
  321.         :XMN_LABEL_STRING "From Files:"
  322.         ))
  323.       
  324.     (setq files_editor_w
  325.       (send XM_TEXT_WIDGET_CLASS :new :managed controlpanel_w
  326.         :XMN_EDIT_MODE :SINGLE_LINE_EDIT))
  327.  
  328.     (setq list_w
  329.       (send List_Browser_Widget_Class :new :managed :scrolled "browser" paned_w
  330.         :xmn_visible_item_count 10
  331.         ))
  332.  
  333.     (setq filename_label_w
  334.       (send XM_LABEL_WIDGET_CLASS :new :managed "label" paned_w
  335.         :xmn_label_string "None"
  336.         ))
  337.  
  338.     (setq viewtext_w
  339.       (send Text_Viewer_Widget_Class :new :managed "view" paned_w
  340.         :XMN_HEIGHT 200
  341.         ))
  342.  
  343.     (send top_w :realize)
  344.  
  345.     ;;
  346.     ;; set constraint resources on controlpanel so that paned window
  347.     ;; doesn't give it resize sashes.
  348.     ;;
  349.     (let (height)
  350.       (send controlpanel_w :get_values :xmn_height 'height)
  351.       ;; In the code below, the kludgery
  352.       ;; "(if (and (eq *MOTIF_VERSION* 1) (eq *MOTIF_REVISION* 0)) ...)"
  353.       ;; is there to work around a name change between Motif 1.0 and 1.1:
  354.       ;; :XMN_MAXIMUM --> :XMN_PANE_MAXIMUM and :XMN_MINIMUM -->:XMN_PANE_MINIMUM
  355.       (send controlpanel_w :set_values
  356.     (if (and (eq *MOTIF_VERSION* 1) (eq *MOTIF_REVISION* 0))
  357.         :XMN_MAXIMUM :XMN_PANE_MAXIMUM)
  358.     height
  359.     (if (and (eq *MOTIF_VERSION* 1) (eq *MOTIF_REVISION* 0))
  360.         :XMN_MINIMUM :XMN_PANE_MINIMUM)
  361.     height
  362.         ))
  363.  
  364.     ;;
  365.     ;; set constraint resources on label widget so that paned window
  366.     ;; doesn't give it resize sashes.
  367.     ;;
  368.     (let (height)
  369.       (send filename_label_w :get_values :xmn_height 'height)
  370.       ;; In the code below, the kludgery
  371.       ;; "(if (and (eq *MOTIF_VERSION* 1) (eq *MOTIF_REVISION* 0)) ...)"
  372.       ;; is there to work around a name change between Motif 1.0 and 1.1:
  373.       ;; :XMN_MAXIMUM --> :XMN_PANE_MAXIMUM and :XMN_MINIMUM -->:XMN_PANE_MINIMUM
  374.       (send filename_label_w :set_values
  375.     (if (and (eq *MOTIF_VERSION* 1) (eq *MOTIF_REVISION* 0))
  376.         :XMN_MAXIMUM :XMN_PANE_MAXIMUM)
  377.     height
  378.     (if (and (eq *MOTIF_VERSION* 1) (eq *MOTIF_REVISION* 0))
  379.         :XMN_MINIMUM :XMN_PANE_MINIMUM)
  380.     height
  381.     ))
  382.  
  383.     ;;
  384.     ;; The doit_button initiates a grep search.
  385.     ;;
  386.     (send doit_button_w :add_callback :XMN_ACTIVATE_CALLBACK '()
  387.       `(
  388.         (send list_w :set_browser_items
  389.           (grep (strcat
  390.              "'"        ;quotify string to protect from shell
  391.              (send ,search_editor_w :get_string) ;string to search for
  392.              "' "
  393.              (send ,files_editor_w :get_string)) ;wildcarded files
  394.             ))
  395.         ))
  396.  
  397.     ;;
  398.     ;; set up a callback on the list widget initialized above such that
  399.     ;; a double click on the browser-item will browse the object.
  400.     ;;
  401.     (send list_w :add_callback :xmn_default_action_callback
  402.       '(callback_item_position)
  403.       `(
  404.         (let* 
  405.         ((browsed-object
  406.           (send ,list_w :get_item_at_position callback_item_position))
  407.          (filename (send browsed-object :file-name))
  408.          (linenum (send browsed-object :line-num))
  409.          )
  410.           (send ,filename_label_w :set_values :xmn_label_string filename)
  411.           (send ,filename_label_w :update_display)    ;incase reading file takes long time
  412.           (send ,viewtext_w :find_file filename linenum)
  413.           ))
  414.       )
  415.     ))
  416.  
  417. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  418. ;;; bring up an instance of the grep browser.
  419. (grep-browser)
  420.