✨ SwiftUI Lifecycle
Is your feature request related to a problem? Please describe.
The current app implementation uses the AppKit lifecycle.
Describe the solution you'd like
Overview
I'd like to see if it's possible to switch to the SwiftUI lifecycle, because this would simplify some parts of the application to a great extent. However, there are some strong requirements that need to be met:
- It may not introduce a significant performance drop
- It may not limit further work on CodeEdit.
Obviously, SwiftUI is not perfect, so not all parts of the app would be modified. For example, SwiftUIs OutlineGroup has bugs and is slow, so our current implementation of NSOutlineView would still be used. The main thing that would be changed would be:
- Window Management
- NSSplitView -> NavigationSplitView
- WorkspaceDocument -> implementation of ReferenceFileDocument
What advantages does this have?
- Less code, while remaining the same functionality
- Use of SwiftUI's toolbar API
- Use of SwiftUI's Command API
- Some problems, like keeping editor state after relaunch, are easier/done automatically in SwiftUI (This also fixes #927 #917)
- Removal of Xib files (interface builder)
- A better foundation if the project would ever go to iPadOS (which may not be impossible anymore if apple would allow apps to be installed outside of the App Store)
What disadvantages does this have?
- Some things SwiftUI does automatically are not the things we want. For example, SwiftUI may choose to open a picker automatically on launch, where we'd like to use our own
WelcomeWindow. However, the issues I've encountered I've already fixed. Other issues might arise while progressing. Otherwise, not a lot of issues have been found. However, there's one catch. Switching to SwiftUI would mean switching fromNSDocumenttoFileDocument. Our current implementation of this isWorkspaceDocument, which would effectively need to be replaced. The unfortunate thing here is that it's quite massive and lots of views depend on it, so lots of views would need to be modified. However, I don't think it's necessarily a bad thing, as: -
WorkspaceDocumentwould need to be modified a lot anyway to add split view. - There are SwiftUI runtime warnings of issues in
WorkspaceDocument. - I think it may be good to split the massive class into smaller classes, to keep things clear.
Describe alternatives you've considered
Keep using AppKit. While this is working fine, it creates lots of boilerplate code. Some parts of the code also have some issues regarding performance. Also, to add split view to the editor, great parts of WorkspaceDocument would need to be modified anyway, so I see this as an opportunity to add this.
Additional context
Progress report:
- [x] Create SwiftUI App lifecycle
Workspace Window
- [x] Create
DocumentGroup&ReferenceFileDocumentfor folders - [ ] Create
DocumentGroup&ReferenceFileDocumentfor an individual file - [x] Create
NSSplitViewwith inspector - [x] Read, edit & save files using
CodeEditTextView - [ ] Modify
OutlineViewto work withFileDocumentinstead ofWorkspaceDocument - [ ] Modify other views to work with
FileDocumentinstead ofWorkspaceDocument
Other windows
- [ ] Move from
NSWindowtoWindow(Not a lot of work) - [ ] Move the settings to
Settings(This is a separate issue, as the settings will be redone anyway. For now, the old settings can be used just as normal.)
@CodeEditApp/maintainers, any thoughts on this?
Although I heavily prefer SwiftUI, I'm hesitant over this decision. Some developers of AuroraEditor said that they are doing the opposite and are removing SwiftUI in certain area's. They gave as example that Tabs in SwiftUI are faster when AppKit is used. (I don't have, or have seen, metrics tho)
I’d also prefer this but only if there is not a performance hit, or at least a significant one. I think it would greatly simplify things, making it much more approachable for other contributors. I am also a big proponent of our code being more declarative. Let’s do some testing around this to see what we are looking at.
As you mentioned, certain things may need to remain in AppKit. For anyone interested, Apple provides a great resource explaining SwiftUI-AppKit interoperability here.
I am gathering that a lot of SwiftUI is based on AppKit. Some of the performance issues are due to some assumptions and lack of customizability. But this may be solvable.
For example, from an article explaining this it says…
Listis not great. The performance with a large number of items (10000+) is unacceptable. The reason is the diff-based mechanism used for computing animations that you can’t disable. If you are considering displaying a large number of items in a List, it most likely won’t work for you.
That is a lot of items and I doubt we will ever use List with this many items so this may not be a concern.
@austincondiff as you may remember the original project navigator suffered from those issues. And since build or dependency directories are usually located in the project directory for most languages (e.g. JS) this had a more than noticeable affect on performance and UX. Expanding a folder sometimes took more than 10 seconds and scrolling performance was less than acceptable - even for small demo projects.
I really like SwiftUI for what it is but in some areas it still isn't mature enough for production use and especially not in an environment where you need loads of customizability and control over certain properties - which you still don't have on SwiftUI.
From my experience using SwiftUI for smaller UI features and certain windows is fine if not even great since it immensely cuts down on boilerplate. But on the flip side of things the core of a large app - especially CodeEdit with multiple windows, split areas, and so on - should be in a stable state which SwiftUI can't deliver at the moment.
As of iOS 15 SwiftUI is pretty usable on iOS and iPadOS but in my opinion it's a different story for macOS as much as I hate that. So I think we should instead simplify our core and get rid of stuff that is no longer needed and improve on what we have. In regards of new contributors we should provide proper documentation for the core components as this is missing at the moment for the most part.
@lukepistrol Now that you mention it, I do remember that bug with the node_modules directory being incredibly slow.
This is the one I think: https://github.com/CodeEditApp/CodeEdit/issues/395
I remember it as well. And completely agree that it is a valid concern.
I've discussed this with @Wouter01 in the past. I have gathered that he plans to leave inperformant views or views that would otherwise be better left in AppKit, in AppKit. This includes the outline view you mention.
Without a shadow of a doubt, there are certain things about SwiftUI that are not ready, but there are certainly parts of it that are. It is very clear to me that SwiftUI is the future. Let's move in that direction where it makes sense to. This way we minimize tech debt in the future when more of SwiftUI becomes more usable.
@lukepistrol I agree that SwiftUI has it's issues and lacks maturity in a lot of ways.
I've had my fair share of issues with SwiftUI, but I've recently seen that window management in SwiftUI has become pretty good with the latest release of macOS. We now have things like openWindow and newDocument, which improve window handling quite a bit.
Basically, I see it this way: SwiftUI's window features are relatively simple wrappers around appkit windows. They require less complexity than let's say List or Form, so it's less of a problem to use them. I've already recreated the basic windows of CodeEdit, like WelcomeView and the main Workspace window, as a document group. I'm partially making use of my package WindowManagement, which adds some missing functionality to SwiftUI windows. My first impressions are that it works quite good, but it needs some polish which I didn't have the time for yet.
I'm certainly open for more discussion around this, as it's important to not make the wrong choice here. If SwiftUI's window management is still to lacking, we indeed shouldn't use it.
@austincondiff: One concern I do have is that we should wait with the transition until we have moved to a Ventura deployment target, since the latest additions in SwiftUI would definitely help.
@matthijseikelenboom: Yeah exactly. And I remember that split views also dis not work that well in SwiftUI.
@Wouter01: What about customization of the top toolbar? like for example if we want to add that center section. Is this possible already? Because back when we started with this project, having even a custom item was not really possible.
To be clear I'm all in to make the move towards SwiftUI - if it makes sense - but there have been a couple of concerns in the past which we need to consider. And I want to be 100% sure it is the right decision before we do, so we don't run into unsolvable issues during/after the process.
Aren't we already on a Ventura deployment target so that we can use ExtensionKit?
What about customization of the top toolbar?
I'd be interested to know this as well!
I want to be 100% sure it is the right decision before we do, so we don't run into unsolvable issues during/after the process.
I completely agree. This is no small decision.
Ultimately, a goal of this project is to adhere to Apple's standards and conventions as close as we can. If Apple sees a big future in SwiftUI and is gravitating in that direction, should we not do the same?
If Apple sees a big future in SwiftUI
The thing is: Why is Apple still updating the "legacy" AppKit and UIKit frameworks as well? I think SwiftUI is and never will be (at least in short term) a replacement but more an augmentation or an abstraction layer of those "legacy" UI frameworks. It's supposed to make it easy to get started building apps and also provide a simple way to create simple view components.
What I want to say is that the goal for Apple is to make it very accessible for beginning developers to get started and make a lot of money through them. Of course they have other ambitions too but recent events regarding Apple make me think this is the main goal all along.
I think they are seeing the rise of other declarative frameworks out there and realized that the amount of code required for someone to write anything is heavier than these other declarative frameworks. I think they saw this and wanted to improve their DX. Sure they always have that dollar sign in mind, but ultimately they have the goal of improving the experience for their developers.
Regardless, we would be treating it the same way. It is not a replacement, but rather a supplement or augmentation. I say if SwiftUI handles window management well, why not take a look at it?
@Wouter01 do you want to link you your POC so we can all take a look at what you are proposing?
@austincondiff: One concern I do have is that we should wait with the transition until we have moved to a Ventura deployment target, since the latest additions in SwiftUI would definitely help.
Oh, I thought this was already decided, as it was also needed to work with ExtensionKit. If we'd need to support Monterey, I agree that it's not a good idea to move to SwiftUI.
@matthijseikelenboom: Yeah exactly. And I remember that split views also dis not work that well in SwiftUI.
Splitviews also have improved a lot in Ventura, but are still not perfect. For example, you can't easily create an inspector-like third column. I've got that to work reliably though, through the use of method swizzling. With that out of the way, the splitview seems to work great.
@Wouter01: What about customization of the top toolbar? like for example if we want to add that center section. Is this possible already? Because back when we started with this project, having even a custom item was not really possible.
https://user-images.githubusercontent.com/62355975/212683389-a239f5bc-52ce-475c-8ffa-1d7e8f93048d.mov
Got it working, but it wasn't easy. There are bugs in how SwiftUI handles spacers, so I've had to hook into SwiftUI to fix that. Also, it was quite the challenge to get the grey center box resizable, but I also didn't get that to work properly in AppKit. For now, I've also made a hook for that in NSToolbar, which will give the item a minSize and maxSize. However, those methods are deprecated and will print warnings.
Oh, I thought this was already decided, as it was also needed to work with ExtensionKit. If we'd need to support Monterey, I agree that it's not a good idea to move to SwiftUI.
Yeah decided but not executed yet 😉
Your POC looks promising!
@austincondiff @lukepistrol Here's a link to the current poc.
Also, @lukepistrol here's my file where I fix all the SwiftUI quirks 🙃
After making good progress on this, I came to the conclusion that it isn't feasible right now due to performance problems with large file trees, because FileWrapper doesn't seem to handle those very well. SwiftUI only allows working with FileWrappers (for now), so there's that. Closing this for now.