Skip to content

Commit ef6ebc8

Browse files
committed
small fixes
fixed some parsing issues and increased the usability of the Goto Declaration command.
1 parent 076873a commit ef6ebc8

File tree

2 files changed

+131
-58
lines changed

2 files changed

+131
-58
lines changed

README.md

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,32 @@ UnrealScript IDE mainly adds better auto-completion features to Sublime Text 2 f
1010
Feautures
1111
------------
1212

13-
* **dynamic, intelligent auto-completion**
13+
* **Dynamic, intelligent auto-completion**
1414
* parameter hints
1515
* display documentation when you need it
1616
* completions feel like the great Sublime Text 2 snippets
1717
* get other completions depending where you are typing (e.g. in the defaultproperties block you only want to get variables)
1818

19-
* **goto declaration and back again** (F10, alt + left, right click menu or via 'Goto' -> 'UnrealScript Goto Declaration')
19+
* **Goto declaration and back again**
20+
* use F10, alt + left click, right click menu or via 'Goto' -> 'UnrealScript Goto Declaration'
21+
* when browsing in the declarations you can always return to your starting position by using one of the above keys when nothing is under your cursor.
2022

21-
* **Add bookmarks to your comments** and navigate to them quickly via Ctrl + R (just write your comments like this: // ! text or /** ! text*/)
23+
* **Add bookmarks to your comments**
24+
* to add a bookmark write your comments like this: // ! text or /** ! text*/
25+
* navigate to them quickly via Ctrl + R
2226

23-
* **more coming...**
27+
* **More coming...**
2428

2529

2630
Planned
2731
------------
2832

29-
* **object-oriented auto-completions**
33+
* **Object-oriented auto-completions**
3034
* if you write e.g. "Controller." you'd want to see it's methods, functions and variables. Currently this doesn't work.
31-
* **add support for enumerations, structs and CONST**
32-
* **multiline function declaration aren't parsed right yet**
35+
* **Object-oriented goto declaration command**
36+
* Goto declaration currently doesn't work on statements such as Controller.bIsPlayer
37+
* **Add support for enumerations, structs and CONST**
38+
* **Your suggestion here...**
3339

3440

3541
Installation
@@ -41,7 +47,7 @@ Installation
4147
2. Search for "inst", hit enter
4248
3. Search for "UnrealScriptIDE", hit enter
4349

44-
**Manually (the idiotically tedious way ;-) ):**
50+
**Manually (not recommended):**
4551

4652
1. Clone or download this package
4753
2. Put it into your Packages directory (find using 'Preferences' -> 'Browse Packages...')
@@ -59,6 +65,7 @@ My auto-complete settings
5965
Here are some relevant settings for auto-completion that I've found quite helpful:
6066

6167
{
68+
"auto_complete_with_fields": true, //this allows auto-completion inside snippets.
6269
"auto_complete_triggers": //this activates auto-completion on '.' and '('
6370
[
6471
{

UnrealScriptAutocomplete.py

Lines changed: 116 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,7 @@
66
# Uses context sensitive completions.
77
#
88
# TODO:
9-
# -autocomplete classes after expand
10-
# -variable read in error: var bool bOne, bTwo, bTrhee; doesn't work yet
11-
# -problematic function declaration:
12-
# native(548) noexport final function bool FastTrace
13-
# (
14-
# vector TraceEnd,
15-
# optional vector TraceStart,
16-
# optional vector BoxExtent,
17-
# optional bool bTraceBullet
18-
# );
9+
# -autocomplete classes after extends
1910
# -load auto complete suggestions from current object before a '.'
2011
# -same for goto definition
2112
#
@@ -68,17 +59,11 @@ def run(self, edit):
6859
window = sublime.active_window()
6960

7061
global last_location, current_location
71-
if last_location != None:
72-
if current_location == active_file:
73-
window.open_file(last_location, sublime.ENCODED_POSITION)
74-
window.open_file(last_location, sublime.ENCODED_POSITION)
75-
last_location = None
76-
return
77-
last_location = None
7862

79-
# Save current position so we can return to it
80-
row, col = self.view.rowcol(self.view.sel()[0].begin())
81-
last_location = "%s:%d" % (active_file, row + 1)
63+
if last_location == None:
64+
# Save current position so we can return to it
65+
row, col = self.view.rowcol(self.view.sel()[0].begin())
66+
last_location = "%s:%d" % (active_file, row + 1)
8267

8368
function = self.get_function(word)
8469
if function != None:
@@ -107,7 +92,18 @@ def run(self, edit):
10792
else:
10893
print _class[1] + 'does not exist'
10994
return
110-
print_to_panel(self.view, word + " not found")
95+
96+
row, col = self.view.rowcol(self.view.sel()[0].begin())
97+
if last_location != None and (word.strip() == "" or col == 0):
98+
if current_location == active_file:
99+
window.open_file(last_location, sublime.ENCODED_POSITION)
100+
window.open_file(last_location, sublime.ENCODED_POSITION)
101+
last_location = None
102+
return
103+
last_location = None
104+
else:
105+
print_to_panel(self.view, word + " not found")
106+
111107
sublime.set_timeout(lambda: self.hide_panel(self.view), OPEN_TIME * 1000)
112108

113109
def get_function(self, name):
@@ -151,7 +147,8 @@ def clear(self):
151147

152148
def add_func(self, function_modifiers, return_type, function_name, arguments, line_number, file_name, description="", is_funct=1):
153149
if self.get_function(function_name) == None:
154-
self._functions.append(Function(function_modifiers, return_type, function_name, arguments, line_number + 1, file_name, description, is_funct))
150+
if function_name != "":
151+
self._functions.append(Function(function_modifiers, return_type, function_name, arguments, line_number + 1, file_name, description, is_funct))
155152

156153
def add_var(self, var_modifiers, var_name, comment, line_number, file_name, description=""):
157154
if self.get_variable(var_name) == None:
@@ -178,11 +175,11 @@ def save_functions_to_list(self, filename):
178175
def get_autocomplete_list(self, word, b_only_var=False):
179176
autocomplete_list = []
180177
for variable in self._variables:
181-
if word in variable.name():
178+
if word.lower() in variable.name().lower():
182179
autocomplete_list.append((variable.name(), variable.name()))
183180
if not b_only_var:
184181
for function in self._functions:
185-
if word in function.function_name():
182+
if word.lower() in function.function_name().lower():
186183
function_str = function.function_name() + '\t(' + function.arguments() + ')' # add arguments
187184
autocomplete_list.append((function_str, function.function_name()))
188185

@@ -242,11 +239,12 @@ def on_query_completions(self, view, prefix, locations):
242239
if current_file != None and is_unrealscript_file(current_file):
243240
# if is in defaultproperties, only get variables:
244241
line_number = 1000000
245-
with open(current_file, 'rU') as file_lines:
246-
for i, line in enumerate(file_lines):
247-
if "defaultproperties" in line.lower():
248-
line_number = i + 1
249-
break
242+
defaultproperties_region = view.find('defaultproperties', 0, sublime.IGNORECASE)
243+
if defaultproperties_region:
244+
(line_number, col) = view.rowcol(defaultproperties_region.a)
245+
else:
246+
return self.get_autocomplete_list(prefix)
247+
250248
(row, col) = view.rowcol(view.sel()[0].begin())
251249
if row > line_number:
252250
return self.get_autocomplete_list(prefix, True)
@@ -383,20 +381,76 @@ def search_file(self, path, file_name):
383381
def save_functions(self, file_name):
384382
with open(file_name, 'rU') as file_lines:
385383
current_documentation = ""
386-
384+
long_line = ""
385+
b_function = True
386+
bBracesNotOnSameLine = False
387387
for i, line in enumerate(file_lines):
388-
if "/**" in line or "//" in line:
388+
if line == "":
389+
continue
390+
if "/**" in line: # start capturing documentation
391+
current_documentation = line
392+
elif line.lstrip() != "" and "/" == line.lstrip()[0] and current_documentation == "":
389393
current_documentation = line
390394

391-
if "function" in line.lower(): # get possible lines containing functions
392-
function_matches = re.search(r'(.*)\bfunction \b(\b.*\b)(.+)\((.*)\)', line) # search for: 1: function modifiers, 2: return type, 3: function name, 4: arguments
393-
if function_matches != None:
394-
if function_matches.group(3) == None or function_matches.group(3) == " ":
395-
pass
396-
#print "not a real function!!! ", line # some wrong lines
395+
if line.lstrip() != "" and (line.lstrip()[0] == '*' or line.lstrip()[0] == '/'): # add to documentation
396+
if current_documentation != line:
397+
current_documentation += line
398+
continue
399+
400+
if bBracesNotOnSameLine:
401+
if ')' in line:
402+
bBracesNotOnSameLine = False
403+
new_line = ' '.join(long_line.split())
404+
function_matches = self.extract_complicated_function(new_line, b_function)
405+
self.collector.add_func(function_matches[0], function_matches[1], function_matches[2], function_matches[3], i, file_name, current_documentation, b_function)
406+
current_documentation = ""
407+
continue
408+
else:
409+
long_line += line
410+
411+
if "function" in line.lower() or "event" in line.lower(): # get possible lines containing functions / events
412+
if "function" in line.lower():
413+
b_function = True
414+
regex_str = r'(.*)\bfunction \b(\b.*\b)(.+)\((.*)\)'
415+
elif "event" in line.lower():
416+
b_function = False
417+
regex_str = r'(.*)\bevent \b(\b.*\b)(.+)\((.*)\)'
418+
419+
matches = re.search(regex_str, line) # search for: 1: modifiers, 2: return type, 3: name, 4: arguments
420+
if matches != None:
421+
if matches.group(3) == None or matches.group(3) == " ": # fail
422+
matches = self.extract_complicated_function(line, b_function) # try again without regex
423+
self.collector.add_func(matches[0], matches[1], matches[2], matches[3], i, file_name, current_documentation, b_function)
424+
current_documentation = ""
425+
continue
397426
else:
398-
self.collector.add_func(function_matches.group(1), function_matches.group(2), function_matches.group(3), function_matches.group(4), i, file_name, current_documentation)
427+
self.collector.add_func(matches.group(1), matches.group(2), matches.group(3), matches.group(4), i, file_name, current_documentation, b_function)
399428
current_documentation = ""
429+
continue
430+
431+
else: # epic fail of my regex, try with python:
432+
if b_function:
433+
if 'function' not in line.split('//')[0]: # the keyword was in the comments
434+
continue
435+
else:
436+
if 'event' not in line.split('//')[0]:
437+
continue
438+
439+
new_line = ' '.join(line.split())
440+
matches = re.search(regex_str, new_line) # search for: 1: modifiers, 2: return type, 3: name, 4: arguments
441+
if matches != None:
442+
if matches.group(3) == None or matches.group(3) == " ":
443+
matches = self.extract_complicated_function(new_line, b_function)
444+
self.collector.add_func(matches[0], matches[1], matches[2], matches[3], i, file_name, current_documentation, b_function)
445+
current_documentation = ""
446+
continue
447+
else:
448+
self.collector.add_func(matches.group(1), matches.group(2), matches.group(3), matches.group(4), i, file_name, current_documentation, b_function)
449+
current_documentation = ""
450+
continue
451+
else:
452+
bBracesNotOnSameLine = True
453+
long_line = new_line
400454

401455
elif "var" in line.lower(): # get possible lines containing variables
402456
# 1: vartype, 2: name, 3: documentation
@@ -422,19 +476,31 @@ def save_functions(self, file_name):
422476
self.collector.add_var(var_line, name, doc_line, i, file_name, current_documentation)
423477
current_documentation = ""
424478

425-
elif "event" in line.lower():
426-
event_matches = re.search(r'(.*)\bevent \b(\b.*\b)(.+)\((.*)\)', line) # search for: 1: event modifiers, 2: return type, 3: event name, 4: arguments
427-
if event_matches != None:
428-
if event_matches.group(3) == None or event_matches.group(3) == " ":
429-
pass
430-
# print "not a real event!!! ", line # some wrong lines
431-
else:
432-
self.collector.add_func(event_matches.group(1), event_matches.group(2), event_matches.group(3), event_matches.group(4), i, file_name, current_documentation, 0)
433-
current_documentation = ""
479+
# manual extraction, because I failed at regex :(
480+
def extract_complicated_function(self, line, b_function):
481+
matches = []
482+
if b_function:
483+
function_split = line.split('function')
484+
else:
485+
function_split = line.split('event')
486+
if len(function_split) > 1:
487+
braces_split = function_split[1].split('(')
488+
else:
489+
return ["", "", "", ""]
434490

435-
if "/**" in current_documentation:
436-
if current_documentation != line:
437-
current_documentation += line
491+
matches.append(function_split[0]) # function modifiers
492+
if len(braces_split[0].split()) > 1: # if name and return:
493+
matches.append(braces_split[0].split()[0]) # return
494+
matches.append(braces_split[0].split()[1]) # name
495+
else:
496+
matches.append('') # no return
497+
matches.append(braces_split[0]) # name
498+
if len(braces_split) > 1:
499+
matches.append(braces_split[1].rstrip('\n\r\t ;)')) # parameters
500+
else:
501+
return ["", "", "", ""]
502+
503+
return matches
438504

439505
def stop(self):
440506
if self.isAlive():

0 commit comments

Comments
 (0)