Removing the extra spacing after colons in function arguments
[macgdbp.git] / Source / DebuggerWindowController.m
1 /*
2 * MacGDBp
3 * Copyright (c) 2002 - 2007, Blue Static <http://www.bluestatic.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17 #import "DebuggerWindowController.h"
18 #import "DebuggerConnection.h"
19 #import "NSXMLElementAdditions.h"
20 #import "AppDelegate.h"
21
22 @interface DebuggerWindowController (Private)
23
24 - (void)updateSourceViewer;
25
26 @end
27
28 @implementation DebuggerWindowController
29
30 /**
31 * Initializes the window controller and sets the connection
32 */
33 - (id)initWithConnection:(DebuggerConnection *)cnx
34 {
35 if (self = [super initWithWindowNibName:@"Debugger"])
36 {
37 _connection = cnx;
38 _expandedRegisters = [[NSMutableArray alloc] init];
39 }
40 return self;
41 }
42
43 /**
44 * Before the display get's comfortable, set up the NSTextView to scroll horizontally
45 */
46 - (void)awakeFromNib
47 {
48 // set up the scroller for the source viewer
49 [_sourceViewer setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
50 [[_sourceViewer textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
51 [[_sourceViewer textContainer] setWidthTracksTextView:NO];
52 [_sourceViewer setHorizontallyResizable:YES];
53 [_sourceViewerScroller setHasHorizontalScroller:YES];
54 [_sourceViewerScroller display];
55 }
56
57 /**
58 * Called when the window is going to be closed so we can clean up all of our stuff
59 */
60 - (void)windowWillClose:(NSNotification *)aNotification
61 {
62 [_connection windowDidClose];
63 }
64
65 /**
66 * Release object members
67 */
68 - (void)dealloc
69 {
70 [_expandedRegisters release];
71
72 [super dealloc];
73 }
74
75 /**
76 * Sets the status and clears any error message
77 */
78 - (void)setStatus:(NSString *)status
79 {
80 [_error setHidden:YES];
81 [_status setStringValue:status];
82 [[self window] setTitle:[NSString stringWithFormat:@"GDBp @ %@:%d/%@", [_connection remoteHost], [_connection port], [_connection session]]];
83
84 [_stepInButton setEnabled:NO];
85 [_stepOutButton setEnabled:NO];
86 [_stepOverButton setEnabled:NO];
87 [_runButton setEnabled:NO];
88 [_reconnectButton setEnabled:NO];
89
90 if ([_connection isConnected])
91 {
92 if ([status isEqualToString:@"Starting"])
93 {
94 [_stepInButton setEnabled:YES];
95 [_runButton setEnabled:YES];
96 }
97 }
98 else
99 {
100 [_reconnectButton setEnabled:YES];
101 }
102 }
103
104 /**
105 * Sets the status to be "Error" and then displays the error message
106 */
107 - (void)setError:(NSString *)error
108 {
109 [_error setStringValue:error];
110 [self setStatus:@"Error"];
111 [_error setHidden:NO];
112 }
113
114 /**
115 * Sets the root node element of the stacktrace
116 */
117 - (void)setStack:(NSArray *)stack
118 {
119 if (_stack != nil)
120 {
121 [_stack release];
122 }
123
124 _stack = stack;
125 [_stack retain];
126
127 if ([_stack count] > 1)
128 {
129 [_stepOutButton setEnabled:YES];
130 }
131 [_stepInButton setEnabled:YES];
132 [_stepOverButton setEnabled:YES];
133 [_runButton setEnabled:YES];
134
135 [self updateSourceViewer];
136 }
137
138 /**
139 * Sets the stack root element so that the NSOutlineView can display it
140 */
141 - (void)setRegister:(NSXMLDocument *)elm
142 {
143 /*
144 [_registerController willChangeValueForKey:@"rootElement.children"];
145 [_registerController unbind:@"contentArray"];
146 [_registerController bind:@"contentArray" toObject:elm withKeyPath:@"rootElement.children" options:nil];
147 [_registerController didChangeValueForKey:@"rootElement.children"];
148 */
149 // XXX: Doing anything short of this will cause bindings to crash spectacularly for no reason whatsoever, and
150 // in seemingly arbitrary places. The class that crashes is _NSKeyValueObservationInfoCreateByRemoving.
151 // http://boredzo.org/blog/archives/2006-01-29/have-you-seen-this-crash says that this means nothing is
152 // being observed, but I doubt that he was using an NSOutlineView which seems to be one f!cking piece of
153 // sh!t when used with NSTreeController. http://www.cocoadev.com/index.pl?NSTreeControllerBugOrDeveloperError
154 // was the inspiration for this fix (below) but the author says that inserting does not work too well, but
155 // that's okay for us as we just need to replace the entire thing.
156 [_registerController setContent:nil];
157 [_registerController setContent:[[elm rootElement] children]];
158
159 for (int i = 0; i < [_registerView numberOfRows]; i++)
160 {
161 int index = [_expandedRegisters indexOfObject:[[[_registerView itemAtRow:i] observedObject] variable]];
162 if (index != NSNotFound)
163 {
164 [_registerView expandItem:[_registerView itemAtRow:i]];
165 }
166 }
167 }
168
169 /**
170 * Forwards the message to run script execution to the connection
171 */
172 - (IBAction)run:(id)sender
173 {
174 [_connection run];
175 }
176
177 /**
178 * Tells the connection to ask the server to reconnect
179 */
180 - (IBAction)reconnect:(id)sender
181 {
182
183 }
184
185 /**
186 * Forwards the message to "step in" to the connection
187 */
188 - (IBAction)stepIn:(id)sender
189 {
190 [_connection stepIn];
191 }
192
193 /**
194 * Forwards the message to "step out" to the connection
195 */
196 - (IBAction)stepOut:(id)sender
197 {
198 [_connection stepOut];
199 }
200
201 /**
202 * Forwards the message to "step over" to the connection
203 */
204 - (IBAction)stepOver:(id)sender
205 {
206 [_connection stepOver];
207 }
208
209 /**
210 * NSTableView delegate method that informs the controller that the stack selection did change and that
211 * we should update the source viewer
212 */
213 - (void)tableViewSelectionDidChange:(NSNotification *)notif
214 {
215 [self updateSourceViewer];
216 }
217
218 /**
219 * Does the actual updating of the source viewer by reading in the file
220 */
221 - (void)updateSourceViewer
222 {
223 int selection = [_stackController selectionIndex];
224 if (selection == NSNotFound)
225 {
226 [_sourceViewer setString:@""];
227 return;
228 }
229
230 // get the filename and then set the text
231 NSString *filename = [[_stack objectAtIndex:selection] valueForKey:@"filename"];
232 filename = [[NSURL URLWithString:filename] path];
233 NSString *text = [NSString stringWithContentsOfFile:filename];
234 [_sourceViewer setString:text];
235
236 // go through the document until we find the NSRange for the line we want
237 int destination = [[[_stack objectAtIndex:selection] valueForKey:@"lineno"] intValue];
238 int rangeIndex = 0;
239 for (int line = 0; line < destination; line++)
240 {
241 rangeIndex = NSMaxRange([text lineRangeForRange:NSMakeRange(rangeIndex, 0)]);
242 }
243
244 // now get the true start/end markers for it
245 unsigned lineStart, lineEnd;
246 [text getLineStart:&lineStart end:NULL contentsEnd:&lineEnd forRange:NSMakeRange(rangeIndex - 1, 0)];
247 NSRange lineRange = NSMakeRange(lineStart, lineEnd - lineStart);
248
249 // colorize it so the user knows which line we're on in the stack
250 [[_sourceViewer textStorage] setAttributes:[NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:[NSColor redColor], [NSColor yellowColor], nil]
251 forKeys:[NSArray arrayWithObjects:NSForegroundColorAttributeName, NSBackgroundColorAttributeName, nil]]
252 range:lineRange];
253 [_sourceViewer scrollRangeToVisible:[text lineRangeForRange:NSMakeRange(lineStart, lineEnd - lineStart)]];
254
255 // make sure the font stays Monaco
256 [_sourceViewer setFont:[NSFont fontWithName:@"Monaco" size:10.0]];
257 }
258
259 /**
260 * Called whenver an item is expanded. This allows us to determine if we need to fetch deeper
261 */
262 - (void)outlineViewItemDidExpand:(NSNotification *)notif
263 {
264 NSLog(@"notification expanded:%@", notif);
265 // XXX: This very well may break because NSTreeController sends us a _NSArrayControllerTreeNode object
266 // which is presumably private, and thus this is not a reliable method for getting the object. But
267 // we damn well need it, so f!ck the rules and we're using it. <rdar://problem/5387001>
268 id notifObj = [[notif userInfo] objectForKey:@"NSObject"];
269 NSXMLElement *obj = [notifObj observedObject];
270
271 // we're not a leaf but have no children. this must be beyond our depth, so go make us deeper
272 if (![obj isLeaf] && [[obj children] count] < 1)
273 {
274 [_connection getProperty:[[obj attributeForName:@"fullname"] stringValue] forElement:notifObj];
275 }
276
277 [_expandedRegisters addObject:[obj variable]];
278 }
279
280 /**
281 * Called when an item was collapsed. This allows us to remove it from the list of expanded items
282 */
283 - (void)outlineViewItemDidCollapse:(id)notif
284 {
285 [_expandedRegisters removeObject:[[[[notif userInfo] objectForKey:@"NSObject"] observedObject] variable]];
286 NSLog(@"outlineViewDidCollapse:%@", notif);
287 }
288
289 /**
290 * Updates the register view by reinserting a given node back into the outline view
291 */
292 - (void)addChildren:(NSArray *)children toNode:(id)node
293 {
294 NSLog(@"addChildren node:%@", node);
295 // XXX: this may break like in outlineViewItemDidExpand:<rdar://problem/5387001>
296 NSIndexPath *masterPath = [node indexPath];
297 for (int i = 0; i < [children count]; i++)
298 {
299 [_registerController insertObject:[children objectAtIndex:i] atArrangedObjectIndexPath:[masterPath indexPathByAddingIndex:i]];
300 }
301
302 [_registerController rearrangeObjects];
303 }
304
305 @end