-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ Placeholder Support #287
Comments
I wonder if we want to go the route VSCode went with placeholders. They call them tab stops, and I think they're a little more flexible than Xcode's in a specific way. I like that Xcode's allow you to create the placeholders by inserting a special character sequence. It allows for copying placeholders from anywhere, and they automatically are formatted so you can tab between them. VSCode's implementation, though, allows you to have named placeholders. For instance, you may have a snippet like this: for (let $1 = 0; $1 < $2.length; $1++) {
const $3 = $2[$1];
} As the user types in $1 or $2, all the other placeholder positions that match that number are filled in. In the example, the user only has to type for (let i = 0; i < array.length; i++) {
const element = array[i];
} This approach may be easier to implement for our case as well. If we're not using a special character sequence, we don't have to modify how text is rendered. Instead, we could insert the placeholders as regular text and keep track of the tab stops as the user edits. We could also try to detect content with placeholders as the user pastes and suggest they paste it as a snippet when it's detected. That would help band-aid share-ability that we lose by not going the Xcode route. |
I like the idea of reusable placeholders. What if we use Xcodes approach but look at the name to see if it is the same? For example: for (let <#iterator#> = 0; <#iterator#> < <#array#>.length; <#iterator#>++) {
const <#element#> = <#array#>[<#iterator#>];
} In this case, placeholders with the same name (e.g., My concern with the simplicity of VS Code's approach is that it may interfere with the syntax of the code in the snippet whereas Xcode's syntax is less likely to interfere. You could always do something like The advantage of VS Code's tab stops approach is that you can customize the order of the tab stops. |
Okay after some more discussion, @austincondiff and I came up with this syntax for placeholders:
When importing snippets from VSCode or TextMates we'll have to convert their syntax We discussed what changes are required for this to work, and it'll require two changes in CodeEditTextView. First is a delegate method for modifying how a selection is updated. So when a user puts a cursor on a placeholder, or selects around it, the selection updates to include the entire placeholder range. Something like protocol SelectionManagerDelegate: AnyObject {
func selectionWillUpdate(selectionManager: SelectionManager, selection: TextSelection, newRange: NSRange) -> NSRange?
} The second change is a change to allow a delegate object to custom render line fragments. This is similar to how NSTextView allows for custom rendering, and would only be triggered by the placeholder drawing code when necessary. This would look something like protocol LineFragmentDrawing {
// return false if not drawn by this method.
func drawLineFragment(ctLine: CTLine, context: CGDrawingContext) -> Bool
} Alternative to the custom drawing method, we could set the font size to 0.1 for the <# and #> characters, which effectively hides those characters entirely. |
Based on our conversation in the weekly meeting:I asked: Placeholder Use Beyond Variable NamesIn Xcode, placeholders are used for more than just variable names. They can represent larger code bodies, for example: if <#condition#> {
<#statements#>
} else {
<#statements#>
} or func <#name#>(<#parameters#>) -> <#return type#> {
<#function body#>
} This illustrates that placeholders often represent different elements of the code structure, not just linked values. I think we need to think beyond variable names when considering placeholder functionality. Namespacing ConcernsOne major issue with "reusable placeholders" is the forced namespacing of placeholder names and values. Consider this snippet: if <#condition#> {
<#statements#>
} else {
<#statements#>
} In this case, the Xcode's Reusable Placeholder WorkaroundAfter further research, I found that Xcode does provide a workaround for reusable placeholders by leveraging multi-cursor editing:
Quirks of Xcode's multi-cursor ImplementationWhile that work around is functional, it has quirks. For example, exiting multi-cursor editing causes the cursor to jump to the last token. This means users need to press Snippet flow can also affect the placeholder navigation: Example 1: var <#variable name#>: <#type#> {
set {
<#variable name#> = newValue
}
get {
<#statements#>
}
} Flow:
Example 2: var <#variable name#>: <#type#> {
get {
<#statements#>
}
set {
<#variable name#> = newValue
}
} Flow:
This shows that the order of the placeholders matters from the perspective of an auto complete snippet. Why I Prefer Xcode-Style Placeholders
On Supporting Other EditorsDuring the meeting, @austincondiff raised an important point about ensuring users of other editors (e.g., VSCode) don’t feel alienated or face difficulty importing snippets. While I agree with this sentiment, I believe we could address it by building a robust snippet importer that converts formats like VSCode’s Looking at vscode-swift's snippets they have adopted vscode's placeholder style. This was an itch that I scratched wondering if placeholder style could be language specific instead of editor specific. I would lean towards aligning Plus, I bet the server-side Swift users would likely appreciate this consistency. Snippet Usage with AI toolsWith the rise of AI tools I would think the reliance on pre-defined snippets (including those benefiting from reusable placeholders) is diminishing. In this context, being more opinionated and Xcode-aligned has fewer drawbacks, especially from a usability and share-ability standpoint. I would vote for a more human readable placeholder over the ability to have fancy snippets. ConclusionsI vote Xcode style placeholders. Any feedback or additional thoughts would be awesome! I'm also very new to this project so I can't help with implementation details but maybe once I get up to speed I can talk more in that area. |
Description
Implement support for placeholders in CodeEdit, similar to Xcode’s
<#placeholder#>
feature. This would allow developers to insert and cycle through editable placeholders in their code, improving productivity and code clarity during development.Use Case
This feature would be particularly useful for defining temporary or template-like code constructs, such as:
Placeholders would:
Expected Behavior
<#placeholder#>
), it should:let <#name#> = <#type#>(<#arguments#>)
).Technical Notes
Steps to Implement
<#placeholder#>
).Additional Context
This feature would align CodeEdit with Xcode’s behavior, making it a more familiar and seamless experience for developers who work on macOS. It also complements other code editing enhancements, such as autocompletion and LSP support.
Screenshots
The text was updated successfully, but these errors were encountered: