├── Support
├── bin
│ ├── ctags
│ └── cscope
└── graffiti.rb
├── Commands
├── Jump back.tmCommand
├── Complete.tmCommand
├── Find definitions of current symbol.tmCommand
├── Find files including current file.tmCommand
├── Jump to Locations of Current Symbol.tmCommand
├── Jump to file including current file.tmCommand
├── Update tags.tmCommand
├── Jump to function calling current function.tmCommand
├── Find Locations of a Symbol___.tmCommand
├── Find Definitions of a Symbol___.tmCommand
├── Find locations of current symbol.tmCommand
├── Jump to definition of current symbol.tmCommand
├── Find functions calling current function.tmCommand
└── Help.tmCommand
├── README.mdown
└── info.plist
/Support/bin/ctags:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textmate/graffiti.tmbundle/master/Support/bin/ctags
--------------------------------------------------------------------------------
/Support/bin/cscope:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/textmate/graffiti.tmbundle/master/Support/bin/cscope
--------------------------------------------------------------------------------
/Commands/Jump back.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | jumpBack()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | keyEquivalent
23 | ^x
24 | name
25 | Jump Back
26 | output
27 | discard
28 | uuid
29 | D3ABB124-274B-4614-8424-BD245BACFE3C
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Commands/Complete.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | completeCurrentWord()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | keyEquivalent
23 | ~
24 | name
25 | Complete
26 | output
27 | discard
28 | uuid
29 | 38FABD8D-4FEB-4D5D-BD76-6D1159C5BD9A
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Commands/Find definitions of current symbol.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | findDefinitionsOfCurrentWord()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | name
23 | Find Definitions of Current Symbol
24 | output
25 | discard
26 | uuid
27 | E7A55A99-65D7-43F9-A35F-E4CEF02382EC
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Commands/Find files including current file.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | findFilesIncludingCurrentFile()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | name
23 | Find Files Including Current File
24 | output
25 | discard
26 | uuid
27 | 8AE754E9-FA13-4C34-969E-6872E30E70B9
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Commands/Jump to Locations of Current Symbol.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | jumpToLocationOfCurrentSymbol()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | name
23 | Jump to Location of Current Symbol
24 | output
25 | discard
26 | uuid
27 | 2CE92A0D-1D44-4D4B-9304-02E13449E79F
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Commands/Jump to file including current file.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | jumpToFileIncludingCurrentFile()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | name
23 | Jump to File Including Current File
24 | output
25 | discard
26 | uuid
27 | 9F156671-94A4-4BDB-AC7A-2EDA8984414D
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Commands/Update tags.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | saveModifiedFiles
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | updateTagFiles()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | keyEquivalent
23 | ^f
24 | name
25 | Update Tags
26 | output
27 | showAsHTML
28 | uuid
29 | 5059ADFA-F217-4BA0-A92D-2001D6465F7F
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Commands/Jump to function calling current function.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | jumpToFunctionCallingCurrentFunction()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | name
23 | Jump to Function Calling Current Function
24 | output
25 | discard
26 | uuid
27 | 1021D5F2-36D1-4C1E-BBA0-A47F6A020F58
28 |
29 |
30 |
--------------------------------------------------------------------------------
/Commands/Find Locations of a Symbol___.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | findLocationsOfPromptedWord()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | keyEquivalent
23 | ^f
24 | name
25 | Find Locations of a Symbol...
26 | output
27 | discard
28 | uuid
29 | 97CF2784-6770-4CF8-A74E-5E5456808251
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Commands/Find Definitions of a Symbol___.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | findDefinitionsOfPromptedWord()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | keyEquivalent
23 | ^f
24 | name
25 | Find Definitions of a Symbol...
26 | output
27 | discard
28 | uuid
29 | EA53FDBC-913F-4591-AADE-3E94A81289C9
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Commands/Find locations of current symbol.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | findLocationsOfCurrentSymbol()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | keyEquivalent
23 | ^f
24 | name
25 | Find Locations of Current Symbol
26 | output
27 | discard
28 | uuid
29 | 946326A3-8BE5-4C0C-8147-9BF6625D4B75
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Commands/Jump to definition of current symbol.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | jumpToDefinitionOfCurrentWord()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | keyEquivalent
23 | ^c
24 | name
25 | Jump to Definition of Current Symbol
26 | output
27 | discard
28 | uuid
29 | 7AEB2540-DB8A-4B77-B499-34BE8285B95A
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Commands/Find functions calling current function.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | autoScrollOutput
6 |
7 | beforeRunningCommand
8 | nop
9 | command
10 | #!/usr/bin/env ruby
11 |
12 | require ENV['TM_BUNDLE_SUPPORT'] + '/graffiti.rb'
13 |
14 | include Graffiti
15 |
16 | findFunctionsCallingCurrentFunction()
17 |
18 | fallbackInput
19 | line
20 | input
21 | none
22 | keyEquivalent
23 | ^f
24 | name
25 | Find Functions Calling Current Function
26 | output
27 | discard
28 | uuid
29 | C51C2C36-3772-46A9-B1EC-29CD380F5C80
30 |
31 |
32 |
--------------------------------------------------------------------------------
/README.mdown:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | You can install this bundle in TextMate by opening the preferences and going to the bundles tab. After installation it will be automatically updated for you.
4 |
5 | # General
6 |
7 | * [Bundle Styleguide](http://kb.textmate.org/bundle_styleguide) — _before you make changes_
8 | * [Commit Styleguide](http://kb.textmate.org/commit_styleguide) — _before you send a pull request_
9 | * [Writing Bug Reports](http://kb.textmate.org/writing_bug_reports) — _before you report an issue_
10 |
11 | # License
12 |
13 | If not otherwise specified (see below), files in this repository fall under the following license:
14 |
15 | Permission to copy, use, modify, sell and distribute this
16 | software is granted. This software is provided "as is" without
17 | express or implied warranty, and with no claim as to its
18 | suitability for any purpose.
19 |
20 | An exception is made for files in readable text which contain their own license information, or files where an accompanying file exists (in the same directory) with a “-license” suffix added to the base-name name of the original file, and an extension of txt, html, or similar. For example “tidy” is accompanied by “tidy-license.txt”.
--------------------------------------------------------------------------------
/info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | contactEmailRot13
6 | znguvrh.tbqneg@tznvy.pbz
7 | contactName
8 | Mathieu Godart
9 | description
10 | The Graffiti TextMate bundle provides a set of commands to manipulate and browse Ruby, C/C++ and Java source code.
11 | mainMenu
12 |
13 | items
14 |
15 | 38FABD8D-4FEB-4D5D-BD76-6D1159C5BD9A
16 | ------------------------------------
17 | 7AEB2540-DB8A-4B77-B499-34BE8285B95A
18 | ------------------------------------
19 | D3ABB124-274B-4614-8424-BD245BACFE3C
20 | ------------------------------------
21 | 9F156671-94A4-4BDB-AC7A-2EDA8984414D
22 | 2CE92A0D-1D44-4D4B-9304-02E13449E79F
23 | 1021D5F2-36D1-4C1E-BBA0-A47F6A020F58
24 | ------------------------------------
25 | E7A55A99-65D7-43F9-A35F-E4CEF02382EC
26 | 8AE754E9-FA13-4C34-969E-6872E30E70B9
27 | 946326A3-8BE5-4C0C-8147-9BF6625D4B75
28 | C51C2C36-3772-46A9-B1EC-29CD380F5C80
29 | ------------------------------------
30 | 97CF2784-6770-4CF8-A74E-5E5456808251
31 | EA53FDBC-913F-4591-AADE-3E94A81289C9
32 | ------------------------------------
33 | 5059ADFA-F217-4BA0-A92D-2001D6465F7F
34 | ------------------------------------
35 | 04CD64C3-29E2-428B-BD66-6B5756740485
36 |
37 | submenus
38 |
39 |
40 | name
41 | Graffiti
42 | ordering
43 |
44 | 38FABD8D-4FEB-4D5D-BD76-6D1159C5BD9A
45 | 7AEB2540-DB8A-4B77-B499-34BE8285B95A
46 | D3ABB124-274B-4614-8424-BD245BACFE3C
47 | 2CE92A0D-1D44-4D4B-9304-02E13449E79F
48 | 1021D5F2-36D1-4C1E-BBA0-A47F6A020F58
49 | 9F156671-94A4-4BDB-AC7A-2EDA8984414D
50 | E7A55A99-65D7-43F9-A35F-E4CEF02382EC
51 | 8AE754E9-FA13-4C34-969E-6872E30E70B9
52 | 946326A3-8BE5-4C0C-8147-9BF6625D4B75
53 | C51C2C36-3772-46A9-B1EC-29CD380F5C80
54 | 97CF2784-6770-4CF8-A74E-5E5456808251
55 | EA53FDBC-913F-4591-AADE-3E94A81289C9
56 | 5059ADFA-F217-4BA0-A92D-2001D6465F7F
57 | 04CD64C3-29E2-428B-BD66-6B5756740485
58 |
59 | uuid
60 | 4477B373-822D-4298-806B-1EF13DBA4FD9
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Commands/Help.tmCommand:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | beforeRunningCommand
6 | nop
7 | command
8 | . "$TM_SUPPORT_PATH/lib/webpreview.sh"
9 | html_header "Graffiti Help" "Graffiti"
10 |
11 | "$TM_SUPPORT_PATH/lib/markdown_to_help.rb" <<'EOF'
12 |
13 | # Introduction
14 |
15 | The Graffiti TextMate bundle provides a set of commands to manipulate and browse source code in Ruby, Makefiles, C/C++, Java, etc. It is based on two commands famous in the Unix world: [CScope][1] and [Exuberant CTags][2].
16 |
17 | For example, it allows you to jump to the definition of a function and then to jump back, it finds all the locations where a symbol can be found, it provides a completion menu made up of all the class, function and variable names found in the code of your project...
18 |
19 | See the *Command List* section for more information on what Graffiti can do for you.
20 |
21 | # First Steps
22 |
23 | Before being able to use any other command of this bundle, you must create the tags, an index of the source code (for each one of your projects).
24 |
25 | To do so, open your project (Graffiti does not work on single documents), call the command **Update tags**. This may take some time on very large projects.
26 |
27 | Graffiti will create an index, recursively, for the source files found in the directory `TM_PROJECT_DIRECTORY`. If you have trouble with this command, check that your environment variable `TM_PROJECT_DIRECTORY` is well defined. This variable can be overwritten in the [Project Information][3] window.
28 |
29 | # Command List
30 |
31 | **Complete** -
32 | Use the `ctags` file to display a list of completion proposals as a popup.
33 |
34 | **Jump to Definition of Current Symbol** -
35 | Ask to `ctags` the locations where the symbol can be found,
36 | ask the user via popup to choose one and jump to it at the proper line.
37 |
38 | **Jump Back** -
39 | Jump to the previous location in the history.
40 |
41 | **Jump to Function Calling Current Function** *(only for C/C++ and Java)* -
42 | Ask to `cscope` where the function under the cursor is called,
43 | ask the user via popup to choose one and jump to it at the proper line.
44 |
45 | **Jump to File Including Current File** *(only for C/C++ and Java)* -
46 | Ask to `cscope` where the current file is #included,
47 | ask the user via popup to choose one and jump to it at the proper line.
48 |
49 | **Find Definitions of Current Symbol** -
50 | Ask to `ctags` where the symbol is defined,
51 | and print it out as a nice HTML list.
52 |
53 | **Find Locations of Current Symbol** *(only for C/C++ and Java)* -
54 | Ask to `cscope` the locations where the symbol can be found,
55 | and print it out as a nice HTML list.
56 |
57 | **Find Functions Calling Current Function** *(only for C/C++ and Java)* -
58 | Ask to `cscope` where the function under the cursor is called,
59 | and print it out as a nice HTML list.
60 |
61 | **Find Files Including Current File** *(only for C/C++ and Java)* -
62 | Ask to `cscope` where the current file is #included,
63 | and print it out as a nice HTML list.
64 |
65 | **Find Definitions of a Symbol...** -
66 | Display a prompt so that the user can enter a symbol,
67 | ask to `cscope` where this symbol is defined,
68 | and print it out as a nice HTML list.
69 |
70 | **Find Locations of a Symbol...** *(only for C/C++ and Java)* -
71 | Display a prompt so that the user can enter a symbol or a regular expression,
72 | ask to `ctags` the locations where this symbol can be found,
73 | and print it out as a nice HTML list.
74 |
75 | **Update Tags** -
76 | Create the `.graffiti` if needed. Create `ctags` and `cscope` tag files
77 | starting from `TM_PROJECT_DIRECTORY`. Display this in a nice HTML output.
78 |
79 | # Configuration
80 |
81 | `TM_PROJECT_DIRECTORY` -
82 | Graffiti create its tags index by recursively looking for all the source code files from the `TM_PROJECT_DIRECTORY` directory. Note that the path to the source files shall not contain spaces (`cscope` seems to have trouble with the space character).
83 |
84 | `.graffiti` -
85 | All the project related files (tag files, history, etc.) are located in this directory. It is created by Graffiti here: `TM_PROJECT_DIRECTORY/.graffiti`.
86 |
87 | # Maintainer
88 |
89 | For questions or sugestions, please contact [Mathieu Godart][4].
90 |
91 | [1]: http://ctags.sourceforge.net
92 | [2]: http://cscope.sourceforge.net/cscope_man_page.html
93 | [3]: http://manual.macromates.com/en/environment_variables#project_dependent_variables
94 | [4]: mathieu.godart@gmail.com
95 |
96 | EOF
97 | fallbackInput
98 | line
99 | input
100 | none
101 | name
102 | Help
103 | output
104 | showAsHTML
105 | uuid
106 | 04CD64C3-29E2-428B-BD66-6B5756740485
107 |
108 |
109 |
--------------------------------------------------------------------------------
/Support/graffiti.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 |
4 | ###############################################################################
5 | # Test cases.
6 | # hal_Open
7 | # memd_FlashOpen
8 | # HAL_ASSERT
9 | # HAL_CFG_CONFIG_T
10 | #
11 |
12 |
13 | ###############################################################################
14 | # The tools `ctags` and `cscope` are in the directory ('$TM_BUNDLE_SUPPORT/bin').
15 | #
16 | require ENV['TM_SUPPORT_PATH'] + '/lib/web_preview.rb'
17 | require ENV['TM_SUPPORT_PATH'] + '/lib/textmate.rb'
18 | require ENV['TM_SUPPORT_PATH'] + '/lib/ui.rb'
19 | require 'yaml'
20 |
21 |
22 | ###############################################################################
23 | # Module Graffiti, containing all the methods and data members of the bundle.
24 | #
25 | module Graffiti
26 |
27 |
28 | ###############################################################################
29 | # Module data members.
30 | #
31 | # Define the locations of the tag and history files.
32 | #
33 | # TODO: check also the TM_PROJECT_FILEPATH variable.
34 | #
35 | @@bundleName = "Graffiti"
36 | @@ctags = "\"#{ENV['TM_BUNDLE_SUPPORT']}/bin/ctags\""
37 | @@cscope = "\"#{ENV['TM_BUNDLE_SUPPORT']}/bin/cscope\""
38 | @@projectDirPath = ENV['TM_PROJECT_DIRECTORY']
39 | @@prefDirName = '.graffiti'
40 | @@prefDirPath = @@projectDirPath.to_s + "/" + @@prefDirName
41 |
42 | @@ctagsTagFileName = 'ctags.tags'
43 | @@ctagsTagFilePath = @@prefDirPath + "/" + @@ctagsTagFileName
44 | @@ctagsTagFileShortPath = @@prefDirName + "/" + @@ctagsTagFileName
45 | @@ctagsIdentifiers = "VOID=void"
46 |
47 | @@cscopeTagFileName = 'cscope.out'
48 | @@cscopeTagFilePath = @@prefDirPath + '/' + @@cscopeTagFileName
49 | @@cscopeTagFileShortPath = @@prefDirName + '/' + @@cscopeTagFileName
50 |
51 | @@cscopeDbFileName = 'cscope.files'
52 | @@cscopeDbFilePath = @@prefDirPath + '/' + @@cscopeDbFileName
53 | @@cscopeDbFileShortPath = @@prefDirName + '/' + @@cscopeDbFileName
54 |
55 | @@historyFilePath = @@prefDirPath + '/history.yaml'
56 | @@debugFilePath = @@prefDirPath + '/debug.log'
57 |
58 |
59 | ###############################################################################
60 | # askCtags
61 | #
62 | # Query `ctags` with a 'symbol' name and return the array 'tagsTable' with
63 | # the list of results.
64 | # This is very similar to 'askCscope' but supports more languages.
65 | #
66 | # 'tagsTable' contains one line per result found. This line contains:
67 | # 0 - File path.
68 | # 1 - Symbol name.
69 | # 2 - Line number.
70 | # 3 - Text of the line where the definition has been found.
71 | # 4 - Tag type.
72 | # 5 - Language type.
73 | # 6 - Signature.
74 | #
75 | # The returned table cannot be null, but can be empty.
76 | #
77 | def askCtags(symbol)
78 | checkTagFiles()
79 |
80 | tagsTable = []
81 | ctagsAskCmd = "grep '^#{symbol}\t.*' #{@@ctagsTagFilePath} | sort -u"
82 |
83 | debugPrint ctagsAskCmd #DEBUG
84 | ctagsCmdResult = `#{ctagsAskCmd}`
85 | ctagsCmdResult.each_line do |line|
86 | lineArray = line.chop.split("\t")
87 | tagsTable << [@@projectDirPath.to_s + "/" + lineArray[1],
88 | lineArray[0],
89 | lineArray[2].to_s.gsub(';"', ''),
90 | lineArray[0] + lineArray[5].to_s.gsub('signature:', ''),
91 | lineArray[3].to_s.gsub('kind:', ''),
92 | lineArray[4].to_s.gsub('language:', ''),
93 | lineArray[5].to_s.gsub('signature:', '')].flatten
94 | end
95 |
96 | return tagsTable
97 | end
98 |
99 |
100 | ###############################################################################
101 | # askCscope
102 | #
103 | # Query `cscope` with a 'symbol' name and a 'cmdId' command number and build
104 | # and return the array 'tagsTable' with query result.
105 | #
106 | # 'tagsTable' contains one line per result found. This line contains:
107 | # 0 - File path.
108 | # 1 - Symbol name.
109 | # 2 - Line number.
110 | # 3 - Text of the line where the definition has been found.
111 | #
112 | # The returned table cannot be null, but can be empty.
113 | #
114 | def askCscope(cmdId, symbol)
115 | checkTagFiles()
116 |
117 | tagsTable = []
118 | # -d Do not update the cross-reference.
119 | # -L Do a single search with line-oriented output.
120 | # -q Enable fast symbol lookup via an inverted index.
121 | cscopeAskCmd = "cd '#{@@projectDirPath}' && " +
122 | "#{@@cscope} -f #{@@cscopeTagFileShortPath} -L -d -q -#{cmdId}\"#{symbol}\""
123 | debugPrint cscopeAskCmd #DEBUG
124 | cscopeCmdResult = `#{cscopeAskCmd}`
125 | cscopeCmdResult.each_line do |line|
126 | lineArray = line.chop.split(" ")
127 | tagsTable << [@@projectDirPath.to_s + "/" + lineArray[0],
128 | lineArray[1..2],
129 | lineArray[3..-1].join(" ")].flatten
130 | end
131 |
132 | return tagsTable
133 | end
134 |
135 |
136 | ###############################################################################
137 | # askToolPopupResults
138 | #
139 | # If 'cmdId' is in 0..8, query `cscope` with a 'symbol' name and a 'cmdId'
140 | # command number, if 'cmdId' is :ctags, query `ctags`. Then ask the user to
141 | # choose one, with a popup menu, if multiple occurrences are found.
142 | #
143 | # Return 'tagsTable' contains one line. This line contains:
144 | # 0 - File path.
145 | # 1 - Symbol name.
146 | # 2 - Line number.
147 | # 3 - Text of the line where the definition has been found.
148 | #
149 | # The returned table cannot be null and cannot be empty. If nothing found
150 | # or selected by user, show a tool tip and exit.
151 | #
152 | def askToolPopupResults(cmdId, symbol)
153 | # Ask to `cscope` the list of locations.
154 | tagsTable = case cmdId
155 | when :ctags then askCtags(symbol)
156 | when 0..8 then askCscope(cmdId, symbol)
157 | end
158 |
159 | if (tagsTable.size == 0) then
160 | # No match.
161 | raise "Nothing found."
162 | elsif (tagsTable.size == 1)
163 | # Only one match.
164 | selected = 0
165 | else
166 | # Multiple occurrences, display a selection menu.
167 | # Build the array 'tagsMenu' containing only the paths.
168 | tagsMenu = []
169 | tagsTable.each do |tagsTableLine|
170 | tagsMenu << tagsTableLine[0].sub(@@projectDirPath, '')
171 | end
172 | selected = TextMate::UI.menu(tagsMenu)
173 | # Esc pressed.
174 | exit if (selected == nil)
175 | end
176 |
177 | # Return the selected file.
178 | return tagsTable[selected]
179 | end
180 |
181 |
182 | ###############################################################################
183 | # displayTagsTable
184 | #
185 | # Get a tags table returned by ask `cscope` function and display it as a list
186 | # in a nice HTML output.
187 | #
188 | def displayTagsTable(title, tagsTable)
189 | raise "Nothing found." if tagsTable.empty?
190 |
191 | # Sort the table according to the file name and line number.
192 | tagsTable.sort! do |x, y|
193 | order = (x[0] <=> y[0])
194 | if order == 0 then
195 | (x[2].to_i <=> y[2].to_i)
196 | else
197 | order
198 | end
199 | end
200 |
201 | html_header(title, @@bundleName)
202 | print "
\n"
203 |
204 | # Used to keep track of the previous filepath, to display or not the file name.
205 | previousFilepath = ""
206 |
207 | tagsTable.each do |tagLine|
208 | filepath = tagLine[0]
209 | fileshortpath = tagLine[0].sub(@@projectDirPath, '')
210 | filename = File.basename(tagLine[0])
211 | symbol = tagLine[1]
212 | line = tagLine[2]
213 | text = tagLine[3]
214 | kind = tagLine[4]
215 | language = tagLine[5]
216 |
217 | # Display the file name and path, only once per file.
218 | unless (previousFilepath == filepath) then
219 | print "- "
220 | # print "In #{filename} - "
221 | # print "
#{fileshortpath}"
223 | print "In the file #{File.dirname(fileshortpath)}/"
224 | print "#{File.basename(filename)} :"
225 | print "
\n"
226 | previousFilepath = filepath
227 | end
228 |
229 | # Display the line and code.
230 | print "Line #{line} "
232 | print "#{text}
\n"
233 | # print "#{text}\n"
234 | # print "#{text}
\n"
235 | end
236 |
237 | print "
\n"
238 |
239 | print "Done. Found #{tagsTable.size} " +
240 | "instance#{"s" if (tagsTable.size > 1)}.
\n"
241 |
242 | html_footer
243 |
244 | TextMate.exit_show_html
245 | end
246 |
247 |
248 | ###############################################################################
249 | # findLocationsOfPromptedWord
250 | #
251 | # Display a prompt so that the user can enter a symbol or a regular expression,
252 | # ask to `cscope` the locations where this symbol can be found,
253 | # and print it out as a nice HTML list.
254 | #
255 | def findLocationsOfPromptedWord()
256 | promptedWord = askWordToUser()
257 | exit if promptedWord.nil?
258 | title = "Locations of \"#{promptedWord}\""
259 | displayTagsTable(title, askCscope(0, promptedWord))
260 | rescue => msg
261 | toolTip(msg)
262 | end
263 |
264 |
265 | ###############################################################################
266 | # findLocationsOfCurrentSymbol
267 | #
268 | # Ask to `cscope` the locations where the symbol can be found,
269 | # and print it out as a nice HTML list.
270 | #
271 | def findLocationsOfCurrentSymbol()
272 | title = "Locations of \"#{getCurrentWord()}\""
273 | displayTagsTable(title, askCscope(0, getCurrentWord()))
274 | rescue => msg
275 | toolTip(msg)
276 | end
277 |
278 |
279 | ###############################################################################
280 | # jumpToLocationOfCurrentSymbol
281 | #
282 | # Ask to `cscope` the locations where the symbol can be found,
283 | # ask the user via popup to choose one and jump to it at the proper line.
284 | #
285 | def jumpToLocationOfCurrentSymbol()
286 | jumpToTagLine(askToolPopupResults(0, getCurrentWord()))
287 | rescue => msg
288 | toolTip(msg)
289 | end
290 |
291 |
292 | ###############################################################################
293 | # findDefinitionsOfPromptedWord
294 | #
295 | # Display a prompt so that the user can enter a symbol,
296 | # ask to `ctags` where this symbol is defined,
297 | # and print it out as a nice HTML list.
298 | #
299 | def findDefinitionsOfPromptedWord()
300 | promptedWord = askWordToUser()
301 | exit if promptedWord.nil?
302 | title = "Definitions of \"#{promptedWord}\""
303 | displayTagsTable(title, askCtags(promptedWord))
304 | rescue => msg
305 | toolTip(msg)
306 | end
307 |
308 |
309 | ###############################################################################
310 | # findDefinitionsOfCurrentWord
311 | #
312 | # Ask to `ctags` where the symbol is defined,
313 | # and print it out as a nice HTML list.
314 | #
315 | def findDefinitionsOfCurrentWord()
316 | title = "Definitions of \"#{getCurrentWord()}\""
317 | displayTagsTable(title, askCtags(getCurrentWord()))
318 | rescue => msg
319 | toolTip(msg)
320 | end
321 |
322 |
323 | ###############################################################################
324 | # jumpToDefinitionOfCurrentWord
325 | #
326 | # Ask to `ctags` where the symbol is defined,
327 | # ask the user via popup to choose one and jump to it at the proper line.
328 | #
329 | def jumpToDefinitionOfCurrentWord()
330 | jumpToTagLine(askToolPopupResults(:ctags, getCurrentWord()))
331 | rescue => msg
332 | toolTip(msg)
333 | end
334 |
335 |
336 | ###############################################################################
337 | # findFunctionsCallingCurrentFunction
338 | #
339 | # Ask to `cscope` where the function under the cursor is called,
340 | # and print it out as a nice HTML list.
341 | #
342 | def findFunctionsCallingCurrentFunction()
343 | title = "Callers of \"#{getCurrentWord()}\""
344 | displayTagsTable(title, askCscope(3, getCurrentWord()))
345 | rescue => msg
346 | toolTip(msg)
347 | end
348 |
349 |
350 | ###############################################################################
351 | # jumpToFunctionCallingCurrentFunction
352 | #
353 | # Ask to `cscope` where the function under the cursor is called,
354 | # ask the user via popup to choose one and jump to it at the proper line.
355 | #
356 | def jumpToFunctionCallingCurrentFunction()
357 | jumpToTagLine(askToolPopupResults(3, getCurrentWord()))
358 | rescue => msg
359 | toolTip(msg)
360 | end
361 |
362 |
363 | ###############################################################################
364 | # findFilesIncludingCurrentFile
365 | #
366 | # Ask to `cscope` where the current file is #included,
367 | # and print it out as a nice HTML list.
368 | #
369 | def findFilesIncludingCurrentFile()
370 | title = "Inclusions of \"#{getCurrentFileName()}\""
371 | displayTagsTable(title, askCscope(8, getCurrentFileName()))
372 | rescue => msg
373 | toolTip(msg)
374 | end
375 |
376 |
377 | ###############################################################################
378 | # jumpToFileIncludingCurrentFile
379 | #
380 | # Ask to `cscope` where the current file is #included,
381 | # ask the user via popup to choose one and jump to it at the proper line.
382 | #
383 | def jumpToFileIncludingCurrentFile()
384 | jumpToTagLine(askToolPopupResults(8, getCurrentFileName()))
385 | rescue => msg
386 | toolTip(msg)
387 | end
388 |
389 |
390 | ###############################################################################
391 | # loadJumpHistory
392 | #
393 | # Return a table containing the previous locations.
394 | # This table can be empty but not null.
395 | #
396 | def loadJumpHistory()
397 | return [] unless FileTest.exist?(@@historyFilePath)
398 | history = File.open(@@historyFilePath) { |yf| YAML::load(yf) }
399 | return [] if history == false
400 | return history
401 | end
402 |
403 |
404 | ###############################################################################
405 | # saveJumpHistory
406 | #
407 | # Save a table containing the previous locations.
408 | # This table can be empty but not null.
409 | #
410 | def saveJumpHistory(history)
411 | File.open(@@historyFilePath, 'w') { |yf| YAML.dump(history, yf) }
412 | end
413 |
414 |
415 | ###############################################################################
416 | # jumpToTagLine
417 | #
418 | # Jump to a location returned by ask `cscope` functions.
419 | #
420 | def jumpToTagLine(tagLine)
421 | jumpToFile(tagLine[0], tagLine[2].to_i, 0)
422 | end
423 |
424 |
425 | ###############################################################################
426 | # jumpToFile
427 | #
428 | # Jump to 'file' at 'line' and 'column' and add the current location to
429 | # the history.
430 | #
431 | def jumpToFile(file, line, column)
432 | # Load the history array.
433 | history = loadJumpHistory()
434 |
435 | # Save the current location in the history array.
436 | history.push({:file => ENV['TM_FILEPATH'], :line => ENV['TM_LINE_NUMBER'].to_i, :column => ENV['TM_COLUMN_NUMBER'].to_i})
437 |
438 | # Save the history array.
439 | saveJumpHistory(history)
440 |
441 | # Open the selected file at the right line and column.
442 | TextMate::go_to({:file => file, :line => line, :column => column})
443 | end
444 |
445 |
446 | ###############################################################################
447 | # jumpBack
448 | #
449 | # Jump to the previous location in the history.
450 | # Delete this location from history.
451 | #
452 | def jumpBack()
453 | # Load the history array.
454 | history = loadJumpHistory()
455 | raise "History is empty." if history.empty?
456 |
457 | # Get the last location from history, remove this location from the
458 | # history and open this location.
459 | TextMate::go_to(history.pop)
460 |
461 | # Save the history array.
462 | saveJumpHistory(history)
463 |
464 | rescue => msg
465 | toolTip(msg)
466 | end
467 |
468 |
469 | ###############################################################################
470 | # completeCurrentWord
471 | #
472 | # Use the `ctags` file to display a list of completion proposals as a popup.
473 | # TODO: Find out why '_' is not handled as a normal char, as expected.
474 | #
475 | def completeCurrentWord()
476 | currentWord = getCurrentWord()
477 | checkTagFiles()
478 |
479 | # Build the list of completion choice.
480 | choices = []
481 | grepCmd = "grep '^#{currentWord}' #{@@ctagsTagFilePath} | " +
482 | "sed -e 's/^\\(#{currentWord}[[:alnum:]_]*\\).*/\\1/p' -e 'd' | sort -u"
483 | `#{grepCmd}`.split("\n").each do |tagLine|
484 | # choices += [{'display' => tagLine, 'insert' => tagLine.sub(currentWord, '')}]
485 | # choices += [{'display' => tagLine, 'match' => tagLine.sub(currentWord, '')}]
486 | choices += [{'display' => tagLine}]
487 | end
488 |
489 | raise "Nothing found." if choices.size == 0
490 |
491 | # Display the completion popup.
492 | options = {:extra_chars => '_', :case_insensitive => false}
493 | TextMate::UI.complete(choices, options)
494 |
495 | rescue => msg
496 | toolTip(msg)
497 | end
498 |
499 |
500 | ###############################################################################
501 | # updateTagFiles
502 | #
503 | # Create the prefDirPath if needed. Create `ctags` and `cscope` tag files
504 | # starting from projectDirPath. Display this in a nice HTML output.
505 | # Check the existence of the project directory.
506 | #
507 | # TODO: Try the option "−L file" of `ctags`.
508 | # TODO: Try the option "−k" of `cscope`.
509 | # TODO: Add a way to exclude some directories.
510 | # TODO: Try to see if it is possible to just update the `cscope` database.
511 | #
512 | def updateTagFiles()
513 | html_header("Updating Tags", @@bundleName)
514 |
515 | # Check that the project directory is defined.
516 | unless (FileTest.directory?(@@projectDirPath.to_s)) then
517 | print "The environment variable TM_PROJECT_DIRECTORY is " +
518 | "not defined. For details, please see First Steps section of the " +
519 | "Graffiti Help command.
\n"
520 | return
521 | end
522 |
523 | if (@@projectDirPath.to_s[' '] != nil) then
524 | print "The environment variable TM_PROJECT_DIRECTORY contains " +
525 | "spaces, sorry but this is not supported by the cscope tool.
\n"
526 | return
527 | end
528 |
529 | print "Updating the tag files for #{@@projectDirPath}.
\n"
530 | print "\n"
531 |
532 | Dir.mkdir(@@prefDirPath) unless FileTest.directory?(@@prefDirPath);
533 |
534 | # Generate the `ctags` tag file.
535 | print "- Updating ctags file...
\n"
536 |
537 | ctagsUpdateCmd = "cd '#{@@projectDirPath}' && " +
538 | "time #{@@ctags} --recurse --extra=+f --fields=-a+i+k+l-m+S+z-s-n-f-K " +
539 | "--excmd=number -I #{@@ctagsIdentifiers} --c-kinds=+p+x " +
540 | "-f \"#{@@ctagsTagFileShortPath}\""
541 |
542 | print ''
543 | debugPrint ctagsUpdateCmd #DEBUG
544 | STDOUT.flush
545 | cmd = open("|#{ctagsUpdateCmd} 2>&1")
546 | cmd.each_line do |line|
547 | STDOUT.flush
548 | print(line)
549 | end
550 | print "Done.\n"
551 |
552 | # Generate the `cscope` tag file.
553 | print " - Updating cscope file...
\n"
554 |
555 | cscopeUpdateCmd = "cd '#{@@projectDirPath}' && " +
556 | "find . -name \\*\.c -o -name \\*\.cpp -o " +
557 | "-name \\*\.h -o -name \\*\.m -o -name \\*\.java " +
558 | "| sed 's/^/\"/; s/$/\"/' > " + # `cscope` does not like the spaces, even escaped.
559 | "'#{@@cscopeDbFileShortPath}' && " +
560 | "time #{@@cscope} -i '#{@@cscopeDbFileShortPath}' -f '#{@@cscopeTagFileShortPath}' -b -q"
561 |
562 | print ''
563 | debugPrint cscopeUpdateCmd #DEBUG
564 | STDOUT.flush
565 | cmd = open("|#{cscopeUpdateCmd} 2>&1")
566 | cmd.each_line do |line|
567 | STDOUT.flush
568 | print(line)
569 | end
570 | print "Done.\n"
571 |
572 | print "
Update complete.\n"
573 |
574 | ensure
575 | html_footer
576 | end
577 |
578 |
579 | ###############################################################################
580 | # toolTip
581 | #
582 | # Show an HTML tooltip displaying 'msg'.
583 | #
584 | def toolTip(msg)
585 | TextMate::UI.tool_tip(msg, {:format => :html})
586 | end
587 |
588 |
589 | ###############################################################################
590 | # checkTagFile
591 | #
592 | # Check that the `ctags` and `cscope` tag files are present.
593 | #
594 | # TODO: Add the check for `cscope`.
595 | #
596 | def checkTagFiles()
597 | raise "No tag file found, please run 'Update Tags' command." unless FileTest.exist?(@@ctagsTagFilePath)
598 | end
599 |
600 |
601 | ###############################################################################
602 | # getCurrentWord
603 | #
604 | # Get the word under the cursor, raise when nothing under the cursor.
605 | #
606 | def getCurrentWord()
607 | currentWord = ENV['TM_CURRENT_WORD']
608 | raise "Nothing under the cursor." if currentWord.nil?
609 | return currentWord
610 | end
611 |
612 |
613 | ###############################################################################
614 | # askWordToUser
615 | #
616 | # Ask the user to provide a word.
617 | #
618 | # TODO: get the default value from the history.
619 | #
620 | def askWordToUser()
621 | options = {:title => 'Symbol to find', :prompt => 'Symbol to find:', :default => ''}
622 | word = TextMate::UI.request_string(options)
623 | return word
624 | end
625 |
626 |
627 | ###############################################################################
628 | # getCurrentFile
629 | #
630 | # Get the basename of the file currently opened, raise when empty (?).
631 | #
632 | def getCurrentFileName()
633 | currentFile = File.basename(ENV['TM_FILEPATH']) # TM_SELECTED_FILE ?
634 | raise "No current file." if currentFile.nil?
635 | return currentFile
636 | end
637 |
638 |
639 | ###############################################################################
640 | # debugPrint
641 | #
642 | # Print out the error message at a location accessible by the developer.
643 | #
644 | def debugPrint(msg)
645 | File.open(@@debugFilePath, "w+") do |file|
646 | file << msg
647 | end
648 | end
649 |
650 |
651 | end
652 |
--------------------------------------------------------------------------------