~ubuntu-branches/debian/stretch/gnome-builder/stretch

« back to all changes in this revision

Viewing changes to doc/DESIGN.md

  • Committer: Package Import Robot
  • Author(s): Andreas Henriksson
  • Date: 2015-10-11 12:38:45 UTC
  • Revision ID: package-import@ubuntu.com-20151011123845-a0hvkz01se0p1p5a
Tags: upstream-3.16.3
ImportĀ upstreamĀ versionĀ 3.16.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# LibIDE Design
 
2
 
 
3
LibIDE is a library that abstracts typical IDE operations.  It is meant to be
 
4
the base library behind Builder.  By separating this into its own static
 
5
library, we make things easier to unit test.  Or at least, that is the hope.
 
6
 
 
7
## Some Open Questions
 
8
 
 
9
 - How do we plumb editor settings in proper order?
 
10
   - Global Settings
 
11
   - Project Settings
 
12
   - Per-file modelines
 
13
 - How do we manage assets such as icons, settings, desktop and service files.
 
14
 - Does it make sense to add/remove/modify translations?
 
15
 - How do we want to plumb templates?
 
16
   Project templates, widget templates, etc.
 
17
   How does the vcs fit in with this.
 
18
 
 
19
## Objects
 
20
 
 
21
### IdeContext
 
22
 
 
23
`IdeContext` is the base object you will deal with in LibIDE. Think of it as a
 
24
library handle. Everything stems from an `IdeContext`.
 
25
 
 
26
Any object that is part of the `IdeContext` can register commands into the
 
27
context. The context has services, a project tree, build system, version
 
28
control system, unsaved files, search engine, and more.
 
29
 
 
30
In Builder, a context would be attached to a GbWorkbench.
 
31
 
 
32
### IdeBuildSystem
 
33
 
 
34
The `IdeBuildSystem` is responsible for loading projects and writing changes to the project back to disk.
 
35
It also registers commands that can be executed to perform transforms on the build system.
 
36
Such transforms might include adding a file.
 
37
 
 
38
### IdeProject
 
39
 
 
40
An `IdeProject` represents the project on disk.  Various subsystems collaborate
 
41
to build the project tree.  Files might come from the VCS. Build system targets
 
42
from the `IdeBuildSystem`.  Class names might come from various symbol
 
43
resolvers.  GtkWidget subclasses (for browsing widgets rather than files) might
 
44
come from another service.
 
45
 
 
46
The build system should update the tree when it performs transforms on the
 
47
underlying build system.  Such changes might include adding a file or target.
 
48
 
 
49
We need a good way to listen for changes on the tree so that UI can update
 
50
iteself.
 
51
 
 
52
### IdeProjectItem
 
53
 
 
54
The `IdeProjectItem` represents an item in the `IdeProject` tree.  What the
 
55
project item contains is backend specific.  IDEs will need to know a bit about
 
56
the backend to render information in the IDE appropriately.
 
57
 
 
58
There will be some known subclasses that IDEs can traverse to find information
 
59
they want to know about.  Files in the project could be one (and loaded by the
 
60
VCS layer).  Targets could be another (and loaded by the build system).
 
61
 
 
62
### IdeLanguage
 
63
 
 
64
`IdeLanguage` represents a programming language, such as C, C++, or Python.  It
 
65
has some general utilities associated with it that can be used in IDEs.  One
 
66
such example is commenting a block of text.  `IdeLanguage` can be used to
 
67
retrieve an `IdeSymbolResolver`, `IdeRefactory`, and others.
 
68
 
 
69
### IdeFile
 
70
 
 
71
An `IdeFile` is an abstraction of a file within the project.  It is partly a
 
72
convenience object so that we can map a file to a language as well as list
 
73
files in the VCS.  `IdeFile` also knows how to load a file from the VCS
 
74
backend.
 
75
 
 
76
### IdeBuffer and IdeBufferIter
 
77
 
 
78
`IdeBuffer` is an interface for passing around buffers that dont require
 
79
copying all of the text out of GtkTextBuffer or GtkTextIter slices.  It also
 
80
allows command handlers to work with a higher level structure than just a
 
81
string buffer.
 
82
 
 
83
### IdeIndenter
 
84
 
 
85
`IdeIndenter` is a class that can help you perform auto indentation in your
 
86
IDE.  Based on the cursor position in the file, it can suggest what the
 
87
indentation should be when various trigger keys are pressed.
 
88
 
 
89
### IdeRefactory
 
90
 
 
91
`IdeRefactory` represents a refactoring engine.  This can be retrieved for a
 
92
given language, and the language can be retrieved from a given file.  The
 
93
refactory can expose available commands that can be executed.  Such an example
 
94
might be a "Extract Method" command.  Most of these will need to be programmed
 
95
into the IDE in a non-generic way.
 
96
 
 
97
### IdeVcs
 
98
 
 
99
An `IdeVcs` represents a version control system.  The version control system
 
100
can perform basic operations like creating a branch, or snapshoting the
 
101
repository.  You can also add and remove files from the VCS, which should be
 
102
performed automatically when performing certain project transforms.
 
103
 
 
104
### IdeUnsavedFiles
 
105
 
 
106
The `IdeUnsavedFiles` object represents the collection of open buffers in the
 
107
IDE.  Many services such as Clang need access to these when determining code
 
108
completion and diagnostics.
 
109
 
 
110
The `IdeUnsavedFiles` class also abstracts the saving of modified buffers to
 
111
the drafts directory.  This allows us to maintain modified buffer state when
 
112
the user closes the window.
 
113
 
 
114
### IdeSearchEngine
 
115
 
 
116
The `IdeSearchEngine` manages search within the IDE.  It can have various
 
117
search providers that can resolve information.  Some search providers might
 
118
even store mined search information on disk for fast future lookup.  Having the
 
119
search engine live in LibIDE allows it fast access to project information,
 
120
files, and refactory information like symbols.
 
121
 
 
122
### IdeSearchProvider
 
123
 
 
124
The `IdeSearchProvider` provides search results to the IdeSearchEngine.
 
125
 
 
126
### IdeSearchResult
 
127
 
 
128
The `IdeSearchResult` represents a search result.  It can be activated to jump
 
129
to a particular file or URI, line number, or other context specific
 
130
information.  IDEs will need to know about search result types to properly
 
131
route to the target information.
 
132
 
 
133
### IdeService
 
134
 
 
135
`IdeService` is a base service that lives inside an `IdeContext`.
 
136
These are used to implement singleton like features that arent quite singletons.
 
137
They are per-context singletons.
 
138
 
 
139
This might be used by something such as a clang indexer to ensure only one
 
140
CXIndex exists per `IdeContext`.
 
141
 
 
142
### IdeDiagnoser
 
143
 
 
144
`IdeDiagnoser` provides access to diagnostics for a given file.  It will take
 
145
the unsaved file state into account via the `IdeUnsavedFiles` attached to the
 
146
`IdeContext`.
 
147
 
 
148
The `IdeDiagnoser` instance is retrieved from the `IdeLanguage` of the
 
149
`IdeFile`.  The `IdeFile` is passed to the `IdeDiagnoser` which will query the
 
150
`IdeClangService`.  The `IdeClangService` will use the unsaved file state in
 
151
`IdeUnsavedFiles` to pass state to the clang API.  Obviously, non-C languages
 
152
will have a service for their features as well (python, gjs, etc).
 
153
 
 
154
The `IdeDiagnoser` for C will be somewhat dependent on a build system since it
 
155
needs access to CFLAGS when communicating with Clang.
 
156
 
 
157
### IdeScript
 
158
 
 
159
An `IdeScript` is a user defined script that can run in the `IdeContext`.  It
 
160
is loaded using a language such as JavaScript to register new commands or tweak
 
161
settings as needed in the context.  For example,
 
162
~/.config/gnome-builder/scripts/*.js might be loaded into the context using
 
163
`IdeScript` to register custom commands.
 
164
 
 
165
### IdeDevice, IdeDeviceProvider, and IdeDeviceManager
 
166
 
 
167
`IdeDevice` represents a device that can run software.
 
168
 
 
169
- It might be your local system, or even an xdg-app runtime on your local
 
170
  system.
 
171
- It might be an externally connected tablet or server.
 
172
- It might be a simulator in an application like Boxes.
 
173
- It might be a remote desktop, possibly alternate operating system.
 
174
 
 
175
The `IdeDeviceProvider` is responsible for discovering devices during device
 
176
settling.  Some devices might support connecting over TCP or Wi-Fi.
 
177
 
 
178
### IdeDebugger
 
179
 
 
180
Fetched via an `IdeDevice`.  Not all devices will support all debuggers.
 
181
Therefore we need to pass an IdeTarget to the device so it can determine if it
 
182
supports it.  pdb for python for example.
 
183
 
 
184
### IdeSymbolResolver
 
185
 
 
186
This is used to list symbols in a document, find a symbol by name, and fetch a
 
187
symbol at a give position in a file.  It should take the contexts unsaved files
 
188
into account.  A symbol resolver for C might access the same clang service that
 
189
is used for diagnostics, sharing their translation units.
 
190
 
 
191
### IdeDeployer
 
192
 
 
193
This is used to deploy a project to a device.  The local device is simpler in
 
194
that it is mostly just a `make install`.
 
195
 
 
196
Remove devices may be more complicated.  This will depend on both the build
 
197
system and target device to work properly.
 
198
 
 
199
Not all combinations will be supportable.
 
200
 
 
201
### IdeExecuter
 
202
 
 
203
This represents a strategy for executing a target on a particular device.
 
204
This is accessed from the device by passing the particular target.
 
205
 
 
206
### IdeProcess
 
207
 
 
208
This represents a subprocess that is executing a target. It could be local or
 
209
on a remote device. This is created by calling `ide_executer_execute()`.
 
210
 
 
211
### IdeTestSuite, IdeTestCase
 
212
 
 
213
Can be fetched from an `IdeBuildSystem`. They should be able to provide an
 
214
`IdeExecutable` that can be used to get an `IdeExecuter` by the `IdeDevice`.
 
215
 
 
216
 
 
217
 
 
218
 
 
219
## Questions and Answers
 
220
 
 
221
### How do I add a GSetting to my application?
 
222
 
 
223
After the IDE presents appropriate UI to the user, the IDE would activate the
 
224
"build-system.gsetting.add" command. Not all build systems may implement this
 
225
command, so it is important that the IDE check that the command is available
 
226
using `ide_context_has_command()`. You can also connect to the `::command-added`
 
227
and `::command-removed` signals which contain detailed quarks for the command
 
228
in question. This should make showing proper UI or enabling/disabling GActions
 
229
easier.
 
230
 
 
231
### How do I add a new executable target to my application?
 
232
 
 
233
Create a new IdeTarget subclass based with the information you desire.
 
234
You can check that the build system supports the target with
 
235
`ide_build_system_supports_target_type()` and providing the `GType`.
 
236
Then call `ide_build_system_add_target()`.
 
237
 
 
238
### How do I add a new C file to my shared library?
 
239
 
 
240
Create a new `IdeFile` using the parameters you want.
 
241
Then use `ide_target_add_file()` to add a file to a target, or another
 
242
interface method based on where you want to add the file.
 
243
`ide_build_system_add_file()` could be used to add the file starting at the
 
244
toplevel.
 
245
 
 
246
### What happens if I try to add a .vala file to a C-based shared library?
 
247
 
 
248
This should be okay if using autotools. So I imagine that based on the target,
 
249
it would accept or reject the item.
 
250
 
 
251
### How do I perform a trigger whenever a file is saved in the IDE?
 
252
 
 
253
In an IDE script, connect to the "file-saved" signal to perform an action.
 
254
The actual save is performed in the default handler, so mutating the content
 
255
can be done by hooking this signal. Using `G_CONNECT_AFTER` when connecting to
 
256
the signal will result in being called after the save has occurred.
 
257
 
 
258
`ide_context_emit_save_file()` and `ide_context_emit_file_saved()` should be
 
259
called by the IDE to trigger any scripts that desire handling the feature.
 
260
 
 
261
```
 
262
Context.connect('save-file', function(file, buffer) {
 
263
    data.replace('\r\n','\n');
 
264
});
 
265
 
 
266
Context.connect('file-saved', function(file, buffer) {
 
267
    console.log('file saved ' + file.get_name() + '\n');
 
268
});
 
269
```
 
270
 
 
271
### How do I get the list of targets found in a project?
 
272
 
 
273
`ide_build_system_list_targets()`
 
274
 
 
275
### How would a golang project be loaded?
 
276
 
 
277
Golang uses a particular directory layout, so a GolangBuildSystem would need to
 
278
be implemented. It would implement various commands for looking up targets and
 
279
building the project. However, no actual project file is used.
 
280
 
 
281
### How can we execute a target without a debugger?
 
282
 
 
283
```c
 
284
executer = ide_device_get_executer (device, target);
 
285
process = ide_executer_execute (executer);
 
286
```
 
287
 
 
288
### How would a user execute a particular, or all, test suites in a project.
 
289
 
 
290
Some build systems might implement an interface method to retrieve a list of
 
291
`IdeTestCase` or `IdeTestSuite`. It should then be possible to get an
 
292
`IdeExecutable` instance for the test that will result in the test being
 
293
executed. In some cases, this might run the test via a helper program such
 
294
as python.
 
295
 
 
296
### How would a user begin debugging a particular target executable on a remote device?
 
297
 
 
298
First we get a handle to the `IdeDebugger` for the `IdeDevice`.
 
299
We may need to specify something like an `IdeTarget` to be able to do so.
 
300
 
 
301
### How would a user get a list of symbols found in the current file?
 
302
 
 
303
First, the IDE would retrieve an `IdeSymbolResolver` for the given `IdeFile`.
 
304
Something like `ide_file_get_symbol_resolver()` seems like an obvious way to
 
305
go. Possibly via the IdeFile language provides a cleaner abstraction.
 
306
 
 
307
Then, use the resolvers interface methods to retrieve the list of symbols
 
308
within the file.
 
309
 
 
310
This does bring up the question of how should we load an IdeSymbolResolver for
 
311
a particular file. It might rely on both the `IdeBuildSystem` and the
 
312
`IdeLanguage` of the file.
 
313
 
 
314
Let's discuss the example of C. If the resolver for C can retrieve the CFLAGS
 
315
for a file using the `IdeBuildSystem`, it need only query the `IdeClangService`
 
316
to retrieve the list of symbols using the tranlsation unit used with the file.
 
317
This means a concrete `IdeCSymbolResolver` concrete implementation.
 
318
 
 
319
An implementation for python, such as `IdePythonSymbolResolver` may be able to
 
320
work simply using the contents of the `IdeFile` since python provides an `AST`
 
321
method.
 
322
 
 
323
### How would a user get the symbol underneath the current cursor?
 
324
 
 
325
Similar to getting the list of symbols, the IDE would get a handle to a resolver
 
326
for the given `IdeFile`. Then it would use the particular method to get the
 
327
symbol underneath the line/column for the cursor.
 
328
 
 
329
### How would a user jump to the definition of a symbol?
 
330
 
 
331
Using the `IdeSymbolResolver` for the `IdeFile`, the IDE would call the method
 
332
to get the location of a particular symbol by name. Then it can open that file
 
333
using it's file loading subsystem.
 
334
 
 
335
### How would a user add a breakpoint to the active debugging process.
 
336
 
 
337
First, the IDE would get a handle to a debugger instance for the current
 
338
execution device. This would likely be performed via the `IdeDevice` that is
 
339
selected for execution. `ide_device_get_debugger()` passing the execution
 
340
target to be executed. Then the device implementation can determine if it has
 
341
a debugger suitable for that execution target.
 
342
 
 
343
Local might support pdb in addition to gdb. However, a tablet/phone might not.
 
344
 
 
345
### How would a user apply a fixit to a file?
 
346
 
 
347
First we access the the `IdeDiagnostics` for the `IdeFile`. Then we iterate
 
348
the available diagnostics that are available. Using one of them, the caller
 
349
can replace each file denoted by the diagnostic with the buffer modifications
 
350
provided.