1/* 2 * This is a THE macro to use the output from ctags; especially Exuberent 3 * Ctags. 4 * To use this macro, define a function key to execute the macro without 5 * any arguments; eg "define F1 macro tags.the" 6 * Then when you want to view the definition of a valid language construct 7 * move the cursor to anywhere on the word and press F1. If the word has 8 * been found in source files by ctags, the file containing the definition 9 * is edited and the cursor moved to the definition line. 10 * 11 * Before this macro can work you need to have run ctags; either external 12 * to THE or by using the 'tags' argument to tags.the. This macro relies 13 * on being able to read the output of the ctags program; a file called 14 * 'tags'. You must specify where this file is as another argument following 15 * 'tags'. eg assume that all source files are in /home/mark/THE, then you 16 * should run: "tags tags /home/mark/THE" 17 * 18 * If you have run ctags outside of THE, you still need to tell tags.the 19 * where the 'tags' file is. This is done by: "tags init /home/mark/THE" 20 * 21 * If you have made significant changes to the source you probably need to 22 * rerun ctags occasionally to bring the 'tags' file into sync with the 23 * source. You can do this while inside THE, by running "tags refresh" 24 * 25 * As mentioned before, tags.the works best with recent versions of 26 * Exuberent Ctags, because it has a recursive flag. If you are using a 27 * version of ctags without the recursive "-R" flag, or you want to use 28 * any other ctags flags when you build your 'tags' file, then the 'tags' 29 * argument to tags.the can be passed any ctags flags. eg: 30 * "tags tags /home/mark/THE * -h junk" 31 */ 32Parse Arg command path options 33Select 34 When command = 'refresh' Then Call refresh path options 35 When command = 'init' Then Call init 'init' path options 36 When command = 'tags' Then Call init 'tags' path options 37 When command = 'prev' Then Call prev 38 When command = 'next' Then Call next 39 When command = 'goto' Then Call goto 40 When command = '' Then Call doit path options 41 Otherwise Call Abort 0,'Invalid option supplied; must be one of "refresh", "init" or empty' 42End 43Return 0 44 45doit: Procedure 46lf = d2c(10) 47'editv get' path 48If path = '' Then Call Abort 0,'You must run tags.the with the "init" or "tags" command first' 49If Stream( path'tags', 'C', 'QUERY EXISTS' ) = '' Then Call Abort 0,'There is no "tags" file in' path 50'extract /curline/fieldword/regexp/cursor/lscreen/' 51fieldword.1 = Strip( fieldword.1) 52tab = d2c(9) 53fn = path'tags' 54save_regexp = regexp.1 55'regexp egrep' 56found.0 = 0 57Call Stream fn, 'C', 'OPEN READ' 58Do While Lines(fn) > 0 59 line = Linein(fn) 60 If Left( line, 2 ) = '!_' Then Iterate 61 Parse Var line keyword (tab) file (tab) location ';' . 62 If keyword = fieldword.1 Then 63 Do 64 idx = found.0 65 idx = idx+1 66 found.idx = file','location 67 found.0 = idx 68 End 69 Else 70 Do 71 If found.0 \= 0 Then Leave 72 End 73End 74Call Stream fn, 'C', 'CLOSE' 75 76Select 77 When found.0 = 0 Then line = '' 78 When found.0 = 1 Then line = found.1 79 Otherwise 80 Do 81 args = '' 82 Do i = 1 To found.0 83 args = args||Strip( Changestr('$/', Changestr( '/^',found.i,'' ), '' ) )lf 84 End 85 If cursor.1 < lscreen.5 % 2 Then 'popup below' lf || args 86 Else 'popup above' lf || args 87 If rc \= 0 | popup.2 = 0 Then line = '' 88 Else 89 Do 90 idx = popup.2 91 line = found.idx 92 End 93 End 94End 95If found.0 \= 0 & line \= '' Then 96 Do 97 Parse Var line file ',' location 98 Call show 99 /* 100 * Now save the current location in a stem 101 */ 102 'editv get TAGS_LAST' 103 If Datatype( tags_last ) = 'NUM' Then next_tag = tags_last+1 104 Else next_tag = 1 105 'editv get TAGS.0' 106 If Datatype( tags.0 ) = 'NUM' Then max_tags = tags.0 107 Else max_tags = 0 108 tags.next_tag = fieldword.1 file location 109 'editv setl TAGS.'next_tag tags.next_tag 110 'editv setl TAGS_LAST' next_tag 111 'editv setl TAGS.0' next_tag 112 Do i = next_tag+1 To max_tags 113 'editv set TAGS.'i 114 End 115 End 116'regexp' save_regexp 117Return 0 118 119prev: Procedure 120'editv get PATH' 121If path = '' Then Call Abort 0,'You must run tags.the with the "init" or "tags" command first' 122'editv get TAGS_LAST' 123If Datatype( tags_last ) \= 'NUM' Then Call Abort 0,'You are at the beginning' 124prev = tags_last - 1 125If prev = 0 Then Call Abort 0,'You are at the beginning' 126 127'extract /regexp' 128save_regexp = regexp.1 129'regexp egrep' 130 131'editv get TAGS.'prev 132Parse Var tags.prev . file location 133Call show 134/* 135 * Now save the current location in a list 136 */ 137'editv setl TAGS_LAST' prev 138'regexp' save_regexp 139Return 0 140 141next: Procedure 142'editv get PATH' 143If path = '' Then Call Abort 0,'You must run tags.the with the "init" or "tags" command first' 144'editv get TAGS_LAST' 145If Datatype( tags_last ) \= 'NUM' Then Call Abort 0,'You are at the end' 146'editv get TAGS.0' 147If Datatype( tags.0 ) = 'NUM' Then max_tags = tags.0 148Else max_tags = 0 149next = tags_last + 1 150If next > max_tags Then Call Abort 0,'You are at the end' 151 152'extract /regexp' 153save_regexp = regexp.1 154'regexp egrep' 155 156'editv get TAGS.'next 157Parse Var tags.next . file location 158Call show 159/* 160 * Now save the current location in a list 161 */ 162'editv setl TAGS_LAST' next 163'regexp' save_regexp 164Return 0 165 166goto: Procedure 167lf = d2c(10) 168'editv get PATH' 169If path = '' Then Call Abort 0,'You must run tags.the with the "init" or "tags" command first' 170'editv get TAGS_LAST' 171If Datatype( tags_last ) \= 'NUM' Then Call Abort 0,'Nothing to show' 172'editv get TAGS.0' 173If Datatype( tags.0 ) \= 'NUM' Then Call Abort 0,'Nothing to show' 174args = '' 175Do i = 1 To tags.0 176 'editv get TAGS.'i 177 Parse Var tags.i key file atag 178 args = args||key'('file')' Strip( Changestr('$/', Changestr( '/^',atag,'' ), '' ) )lf 179End 180'popup centre initial' tags_last lf || args 181If rc \= 0 | popup.2 = 0 Then Nop 182Else 183 Do 184 idx = popup.2 185 'extract /regexp' 186 save_regexp = regexp.1 187 'regexp egrep' 188 'editv get TAGS.'idx 189 Parse Var tags.idx . file location 190 Call show 191 /* 192 * Now save the current location in a list 193 */ 194 'editv setl TAGS_LAST' idx 195 'regexp' save_regexp 196 End 197Return 198 199Escape: Procedure 200Parse Arg str 201str = Changestr( '*', str, '\*' ) 202str = Changestr( '[', str, '\[' ) 203str = Changestr( ']', str, '\]' ) 204str = Changestr( '(', str, '\(' ) 205str = Changestr( ')', str, '\)' ) 206Return str 207 208Init: Procedure 209Parse Arg type path options 210'extract/version' 211If version.3 = 'UNIX' | version.3 = 'X11' | version.3 = 'QNX' Then ossep = '/' 212Else ossep = '\' 213If path = '' Then Call Abort 0,'Must supply a path for "'type'" command' 214here = Stream( path, 'C', 'QUERY EXISTS' ) 215If here = '' Then Call Abort 0,path 'does not exist' 216If Right( here, 1 ) \= ossep Then path = here||ossep 217Else path = here 218'editv set path' path 219If type = 'tags' Then Call Runctags options 220Return 0 221 222Refresh: Procedure 223Parse Arg args 224If args \= '' Then Call Abort 0,'No parameters should be supplied with "refresh" command' 225Call Runctags 226Return 0 227 228Runctags: Procedure 229Parse Arg options 230'editv get' path 231If path = '' Then Call Abort 0,'You must run tags.the with the "init" command first' 232here = Directory() 233If Directory( path ) = '' Then Call Abort 1, path, 'does not exist' 234If options = '' Then Address System 'ctags -R *' With Output Stem junk. Error Stem err. 235Else Address System 'ctags' options With Output Stem junk. Error Stem err. 236If rc \= 0 Then 237 Do i = 1 To err.0 238 'emsg' err.i 239 End 240Call Directory here 241Return 0 242 243show: 244'the' path||file 245'top' 246If Datatype( location ) = 'NUM' Then 247 Do 248 ':'location 249 '-1' 250 'l r /^.*$/' 251 End 252Else 'locate r' Escape(location) 253If incommand() Then 'cursor home' 254Return 255 256Abort: Procedure 257Parse Arg reset,msg 258'emsg' msg 259If reset Then 'editv set path' 260Exit 0 261