Version 12 of FindWords utility

Updated 2004-01-26 15:02:33

ulis, 2004-01-20. FindWords is an editor utility that let you jump to another occurrence of the selected string. Designed for Textpad it can be used (modified) for other editors.

Modified 2004-01-25: Added quotes around the $Sel arg to deal with strings containing spaces.

Modified 2004-01-26: Added keyboard support.


A snapshot

http://perso.wanadoo.fr/maurice.ulis/tcl/FindWords.png


The script

  #########################
  #
  # FindWords: jump to a string (Textpad utility)
  #
  # (C) 2004, ulis; NOL
  #
  # -----------------------
  # input: source file, selected string
  # output: exec of a script
  #########################

  if 0 \
  {
    # Abstract

    This script let you see a listbox with all the occurrences of the selected string,
      select one of them and have the text cursor positionned in front of the selected one.

    # Install

    For Textpad:

      - Optional: copy the DDEOPN32.EXE utility from the Textpad system directory
        to the Windows sytem32 or system directory
      - Put FindWords.tcl & FindWords.cfg in the TextPad system directory (or elsewhere)
      - With the /Configure/Preferences menu add a new tool with:
          - Commands        = <the path of wish>
          - Parameters      = <the path of this file> $File "$Sel"
          - Initial folder  = $FileDir
      - Rename this tool: FindWords
      - Modify FindWords.cfg
        exec = <script to execute to go to the word> (where you can have to set the DDEOPN32.EXE path)
                 inside this script: 
                    %FileName% will be replaced by the Tcl source file name
                    %Line% will be replaced by the line where is the string.
                    %Char% will be replaced by the number of the char where start the string.
        options = <space separated list of key/value pairs>
                 -over <boolean>
                    0 : don't search for overlapping strings
                    1 : search for overlapping strings
                 -thick <integer>
                    thickness of the closeness (in chars)
        @exec, @options : Tcl script returning a value for exec or options
      - Optional: add a key accelerator with /Configure/Preferences/Keyboard/Categories/Utilities

    # Use

    From the Tcl/Tk text window select the /Tools/FindWords menu
    Click the right line inside the listbox
  }

  # ------------------
  # GetWords
  #
  # ------------------
  # returns a list of lines description
  #   in the form of {line-# char-# closeness}
  # ------------------

  proc GetWords {} \
  {
    variable {}
    # get string
    set string $(string)
    # open Tcl source file
    set fn $(fn)
    if {![catch { open $fn } res]} { set fp $res } \
    else { tk_messageBox -message $res; exit }
    # loop thru lines
    set l 1
    if {$(-over)} { set l [string len $string] }
    set strs {}
    set lines {}
    set ln 0
    while {![eof $fp]} \
    {
      # get a line
      set line [string trimleft [gets $fp]]
      lappend lines $line
      # search for the string inside the line
      set cn 0
      while {$cn > -1} \
      {
        set cn [string first $string $line $cn]
        if {$cn > -1} \
        { lappend strs [list $ln $cn]; incr cn $l }
      }
      # update current line number
      incr ln
    }
    close $fp
    set (strs) $strs
    set (lines) $lines
  }

  # ------------------
  # GotoWord
  #
  # ------------------
  # exec's the (script) to go to the string
  # ------------------

  proc GotoWord {} \
  {
    variable {}
    set index [.lb curselection]
    if {$index == ""} { return }
    foreach {ln cn} [lindex $(strs) $index] break
    set fn [string map {\\ /} $(fn)]
    set script [string map [list %FileName% $fn %Line% [incr ln] %Char% [incr cn]] $(exec)]
    catch { eval $script } msg
    if {$msg != ""} { tk_messageBox -message $msg }
    exit
  }

  # ------------------
  # SetParms
  #
  # ------------------
  # sets the (keys) & (script) parameters
  # ------------------

  proc SetParms {} \
  {
    variable {}
    set (exec) "exec DDEOPN32.EXE Textpad \"%FileName%(%Line%,%Char%)\""
    set (opts) {-font {Courier 9} -over 0 -thick 10}
    set fn [file join [file dirname [info script]] FindWords.cfg]
    if {![catch { open $fn } res]} { set fp $res } \
    else { tk_messageBox -message $res; exit }
    while {![eof $fp]} \
    {
      set line [string trimleft [gets $fp]]
      switch -glob -- $line \
      {
        ""    -
        \;*   -
        \[*   -
        #*    { set key "" }
        exe*  { set key exec }
        opt*  { set key opts }
        @exe* { set key @exec }
        @opt* { set key @opts }
        default \
        { tk_messageBox -message "unknown key \"$line\" in config file"; exit } 
      }
      if {$key == ""} { continue }
      set n [string first = $line]
      if {$n == -1} \
      { tk_messageBox -message "wrong line \"$line\" in config file"; exit } 
      set value [string trim [string range $line $n end] " ="]
      set ($key) $value
      if {[string match @* $key]} \
      {
        set key [string range $key 1 end]
        set ($key) [$value]
      }
    }
    close $fp
    # get options
    foreach {option value} $(opts) \
    {
      switch -glob -- $option \
      {
        -f*     { set key -font }
        -o*     { set key -over }
        -t*     { set key -thick }
        default \
        { tk_messageBox -message "unknown option \"$option\" in config file"; exit } 
      }
      set ($key) $value
    }
  }

  # ------------------
  # ChooseWord
  #
  # ------------------
  # presents the listbox with all strings occurrence
  # ------------------

  proc ChooseWord {} \
  {
    variable {}
    wm withdraw .
    set (fn) [lindex $::argv 0]
    set (string) [lindex $::argv 1]
    if {$(string) == ""} \
    { tk_messageBox -message "word is empty"; exit } 
    SetParms
    GetWords
    if {[llength $(strs)] == 0} \
    { tk_messageBox -message "no word found"; exit } 
    wm deiconify .
    wm title . "FindWord \"$(string)\""
    listbox .lb -font $(-font) -yscrollc {.vs set} -activestyle none
    scrollbar .vs -command {.lb yview}
    grid .lb -row 0 -column 0 -sticky nsew
    grid .vs -row 0 -column 1 -sticky ns
    grid rowconfigure . 0 -weight 1
    grid columnconfigure . 0 -weight 1
    bind .lb <ButtonRelease-1> GotoWord
    bind .lb <KeyPress-Return> GotoWord
    set height 0
    set width 0
    set t $(-thick)
    set l [string length $(string)]
    set l [expr {$l + $t - 1}]
    foreach item $(strs) \
    { 
      foreach {ln cn} $item break
      set line [lindex $(lines) $ln]
      set n1 $cn; incr n1 -$t
      set n2 $cn; incr n2 $l
      set string [string range $line $n1 $n2]
      set item "$ln,$cn: $string"
      .lb insert end $item
      incr height
      set length [string length $item]
      if {$width < $length} { set width $length }
    }
    if {$height > 40} { set height 40 }
    if {$height < 10} { set height 10 }
    if {$width > 80} { set width 80 }
    if {$width < 20} { set width 20 }
    .lb config -width $width -height $height
    .lb selection set 0
    focus -force .lb
    focus -force .
    raise .
  }

  # ========
  #
  # let's go
  #
  # ========

  package require Tk
  ChooseWord

The config file

  # ---------------------
  # FindWords config file
  # ---------------------

  exec = exec DDEOPN32.EXE Textpad "%FileName%(%Line%,%Char%)"
  options = -font {Courier 9} -over 0 -thick 15

Peter Lewerin your introduction seems to imply that it's OK to modify and reuse this code. Maybe it would be a good idea to make an explicit statement to that effect next to the (c) notice (this being a Wiki, I could add such a statement, but somehow it doesn't seem right :-) ).

ulis In short: yes you can. See Who owns the content on this Wiki. The used licence, NOL, means: No Obligation Licence. For you, as for me.

(PL) : I know I can, but in many cases we shouldn't make modifications. For instance, editing the terms of use of someone else's source code qualifies as evil for me. Thanks for the clarification, I wasn't familiar with the acronym, NOL.

ulis Sorry for the misuse of the verb: I don't speak english and have to survive with that. Feel free to correct the offending word. And yes the ability(?) given to everybody to change the content of the Wiki has some moral limits (we are between gentlemen ;^)).


Category Editor utility