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.
9
- How do we plumb editor settings in proper order?
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.
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`.
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.
30
In Builder, a context would be attached to a GbWorkbench.
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.
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.
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.
49
We need a good way to listen for changes on the tree so that UI can update
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.
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).
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.
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
76
### IdeBuffer and IdeBufferIter
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
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.
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.
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.
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.
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.
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.
122
### IdeSearchProvider
124
The `IdeSearchProvider` provides search results to the IdeSearchEngine.
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.
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.
139
This might be used by something such as a clang indexer to ensure only one
140
CXIndex exists per `IdeContext`.
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
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).
154
The `IdeDiagnoser` for C will be somewhat dependent on a build system since it
155
needs access to CFLAGS when communicating with Clang.
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.
165
### IdeDevice, IdeDeviceProvider, and IdeDeviceManager
167
`IdeDevice` represents a device that can run software.
169
- It might be your local system, or even an xdg-app runtime on your local
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.
175
The `IdeDeviceProvider` is responsible for discovering devices during device
176
settling. Some devices might support connecting over TCP or Wi-Fi.
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.
184
### IdeSymbolResolver
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.
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`.
196
Remove devices may be more complicated. This will depend on both the build
197
system and target device to work properly.
199
Not all combinations will be supportable.
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.
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()`.
211
### IdeTestSuite, IdeTestCase
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`.
219
## Questions and Answers
221
### How do I add a GSetting to my application?
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
231
### How do I add a new executable target to my application?
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()`.
238
### How do I add a new C file to my shared library?
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
246
### What happens if I try to add a .vala file to a C-based shared library?
248
This should be okay if using autotools. So I imagine that based on the target,
249
it would accept or reject the item.
251
### How do I perform a trigger whenever a file is saved in the IDE?
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.
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.
262
Context.connect('save-file', function(file, buffer) {
263
data.replace('\r\n','\n');
266
Context.connect('file-saved', function(file, buffer) {
267
console.log('file saved ' + file.get_name() + '\n');
271
### How do I get the list of targets found in a project?
273
`ide_build_system_list_targets()`
275
### How would a golang project be loaded?
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.
281
### How can we execute a target without a debugger?
284
executer = ide_device_get_executer (device, target);
285
process = ide_executer_execute (executer);
288
### How would a user execute a particular, or all, test suites in a project.
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
296
### How would a user begin debugging a particular target executable on a remote device?
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.
301
### How would a user get a list of symbols found in the current file?
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.
307
Then, use the resolvers interface methods to retrieve the list of symbols
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.
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.
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`
323
### How would a user get the symbol underneath the current cursor?
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.
329
### How would a user jump to the definition of a symbol?
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.
335
### How would a user add a breakpoint to the active debugging process.
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.
343
Local might support pdb in addition to gdb. However, a tablet/phone might not.
345
### How would a user apply a fixit to a file?
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