Skip to content

Commit 193cd9b

Browse files
committed
Initial documentation
1 parent c193434 commit 193cd9b

3 files changed

Lines changed: 106 additions & 0 deletions

File tree

Documentation/Overview.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Documentation of the SwiftUI view `CodeEditor`
2+
3+
4+
`CodeEditor` is a SwiftUI view implementing a general-purpose code editor. It works on macOS (from 11.0) and on iOS (from 14.0). As far as prossible, it tries to provide the same functionality on macOS and iOS, but this is not always possible because the iOS version of TextKit does miss some of the APIs exposed on macOS, such as the type setter API. The currently most significant omission on iOS is the minimap.
5+
6+
7+
## The main view
8+
9+
Typical usage of the `CodeEditor` view is as roughly follows.
10+
11+
```swift
12+
struct ContentView: View {
13+
@State private var text: String = "My awesome code..."
14+
@State private var messages: Set<Located<Message>> = Set ()
15+
16+
@Environment(\.colorScheme) private var colorScheme: ColorScheme
17+
18+
var body: some View {
19+
CodeEditor(text: $text, messages: $messages, language: .swift)
20+
.environment(\.codeEditorTheme,
21+
colorScheme == .dark ? Theme.defaultDark : Theme.defaultLight)
22+
}
23+
}
24+
```
25+
26+
The view expects three arguments:
27+
28+
1. a binding to a `String` that contains the edited text,
29+
2. a binding to a set of the currently reported `Messages` pertaining to individual lines of the edited text, and
30+
3. a language configuration that controls language-specific editing suppport such as syntax highlighting.
31+
32+
Moreover, a `CodeEditor` honours the `codeEditorTheme` environment variable, which determines the theme to use for syntax highlighting.
33+
34+
To see a complete working example, see the [CodeEditorView demo app](https://github.com/mchakravarty/CodeEditorDemo).
35+
36+
37+
## Messages
38+
39+
Messages are notifications that can be reported on a line by line basis. They can be created using the following initialiser:
40+
41+
```swift
42+
init(category: Message.Category, length: Int, summary: String, description: NSAttributedString?)
43+
```
44+
45+
The message category determines the type of message, the length are the number of characters that ought to be marked (but this is not implemented yet). The summary is a short form of the message used inline on the right hand side of the code view, whereas the description an optional more detailed version specifies. For example, a summary could be that there is a type error and the description could explain the nature of the type error in more detail.
46+
47+
Initially, the summary is displayed inline. Once the user clicks or taps on the summary, the detailed description is shown in a popup. Clicking or tapping on the detailed description collapses it again.
48+
49+
New messages are reported by adding them to the set. Similarily, they can be removed the message set to retract them. The code editor will also automatically remove any messages on lines that have been edited.
50+
51+
### Locations
52+
53+
Messages are `Located` by way of a generic wrapper:
54+
55+
```swift
56+
struct Located<Entity> {
57+
let location: Location
58+
let entity: Entity
59+
}
60+
61+
struct Location {
62+
let file: FilePath
63+
let line: Int
64+
let column: Int
65+
}
66+
```
67+
68+
`Location.line` determines the line at which a message is going to be displayed. During editing, messages stick to the lines at which they are reported. For example, if the user adds additional lines before the line at which a message got reported, the message will stick to its original line moving down with it. Note however, that the `Located` wrapper does not get updated in that process, it always specifices the initial line number at the time of reporting. Messages conform to `Identifable` to enable distinguishing between them independently of the reporting location.
69+
70+
### Categories
71+
72+
Currently, four categories are supported (in order of priority): `.live`, `.error`, `.warning`, and `.informational`. The message category is used to selected a message colour out of a message theme. That colour is used as a background when rendering the message and also to highlight the line at which a message gets reported. If multiple messages are reported on the same line, the colour of the inline version (and line highlight) is determined by the message of the highest priority.
73+
74+
Currently, the message theme is hardcoded, but it will become configurable in the future. (Details are still to be determined.)
75+
76+
77+
## Language configurations
78+
79+
`LanguageConfiguration`s determine syntaxtic properties, which are used for syntax highlight, bracket matching, and similar syntax-dependent functionality. More precisely, language confugurations provide information that enables the code editor to tokenise the edited code in real time using a custom tokeniser based on `NSRegularExpression`. Tokenisers are finite-state machines (FSM) whose state transitions dependent on the matched regular expressions and who use different regular expressions depending on the FSM state. This enables us to tokenise differently depending on whether we are, for example, in a nested comment or in plain code. The tokeniser is a generic extension of `NSMutableAttributedString` (contained in the file `MutableAttributedString.swift`) and may be of independent interest.
80+
81+
A language configuration specifies language-dependent tokenisation rules in the form of a struct that determines what comment delimiters to use, regular expressions for string and numeric literals as well as for identifiers. The configuration options are currently still fairly limited. Example configurations for Swift and Haskell are included. Configurations for other languages can be defined in a similar manner.
82+
83+
84+
## Syntax highlighting
85+
86+
Syntax highlighting is currently completely static and only based on token classification. Longer term, the aim is to have basic highlighting on the basis of token classification (as now) in combination with semantic highlighting on the basis of code analysis as performed, for example, by SourceKit.
87+
88+
The tokeniser depending on the language configuration uses two new `NSAttributedString.Key`s to mark comments with `.comment` and general tokens with `.token`. The token attribute value is of type `LanguageConfiguration.Token` and gets continously updated as the text edited. For optimal performance, we use on-the-fly custom attribute translation (in a custom subclass of the `NSTextStorage` class cluster, called `CodeStorage`). Moreover, syntax highlighting only varies the foreground colour of tokens to keep type setting independent of highlighting.
89+
90+
NB: Temporary attributes are no option, because they are no supported by `NSLayoutManager` on iOS.
91+
92+
### Themes
93+
94+
The `Theme` struct determines a font name and a font size together with colours for the various recognised types of tokens and for general colour elements, such as the cursor colour, selection colour, and so on. On iOS, TextKit doesn't allow us to customise the cursor and selection colour idenpendently. Hence, we derive an appropriate tint colour from the theme's selection colour.

Documentation/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Documentation of CodeEditorView
2+
3+
This directory contains the conceptual [documentation](Overview.md) for the SwiftUI `CodeEditor` view.
4+

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ The following is the default light theme on iOS. Both line highlighting and the
1212

1313
<img src="app-demo-images/iOS-light-example.png">
1414

15+
1516
## How to use it
1617

1718
Typical usage of the view is as follows.
@@ -31,10 +32,17 @@ struct ContentView: View {
3132
}
3233
```
3334

35+
3436
## Demo app
3537

3638
To see the `CodeEditorView` in action, have a look at the repo with a [cross-platform demo app](https://github.com/mchakravarty/CodeEditorDemo).
3739

40+
41+
## Documentation
42+
43+
For more information, see the [package documentation](Documentation/Overview.md).
44+
45+
3846
## License
3947

4048
Copyright 2021 Manuel M. T. Chakravarty.

0 commit comments

Comments
 (0)