Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/scripts/get-tuist-version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import json
import os
from pathlib import Path
import sys
import urllib.error
import urllib.request
Expand All @@ -26,6 +27,14 @@
version = None
page = 1
last_payload = None

repo_root = Path(__file__).resolve().parents[2]
version_file = repo_root / ".tuist-version"
if version_file.exists():
pinned_version = version_file.read_text(encoding="utf-8").strip()
if pinned_version:
version = pinned_version

while page <= max_pages and not version:
url = f"https://api.github.com/repos/tuist/tuist/releases?per_page={per_page}&page={page}"
request = urllib.request.Request(url, headers=headers)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ on:
jobs:
markdown-validation:
# Temporarily disable Markdown linting until the rules are re-enabled.
if: ${{ false }}
if: ${{ github.ref == 'refs/heads/__disabled_markdown_validation__' }}
name: Markdown Validation
runs-on: ubuntu-22.04
steps:
Expand Down
22 changes: 14 additions & 8 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ on:
- 'Sources/**'
- 'Tests/**'
- 'scripts/**'
- '.github/scripts/get-tuist-version.py'
- 'Package.swift'
- 'Package.resolved'
- 'Project.swift'
- 'Workspace.swift'
- '.tuist-version'
- 'ISOInspector.xcodeproj/**'
- 'ISOInspector.xcworkspace/**'
- '.github/workflows/*.yml'
Expand All @@ -23,10 +25,12 @@ on:
- 'Sources/**'
- 'Tests/**'
- 'scripts/**'
- '.github/scripts/get-tuist-version.py'
- 'Package.swift'
- 'Package.resolved'
- 'Project.swift'
- 'Workspace.swift'
- '.tuist-version'
- 'ISOInspector.xcodeproj/**'
- 'ISOInspector.xcworkspace/**'
- '.github/workflows/*.yml'
Expand All @@ -39,6 +43,16 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4

- name: Select Xcode 16.2
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "16.2"

- name: Show Xcode and Swift versions
run: |
xcodebuild -version
swift --version

- name: Determine Tuist CLI release
id: tuist-version
env:
Expand Down Expand Up @@ -81,14 +95,6 @@ jobs:
- name: Show Tuist version
run: tuist version

- name: Select Xcode 16.2
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: "16.2"

- name: Show Xcode version
run: xcodebuild -version

- name: Validate Tuist project definition
run: tuist dump project > /dev/null

Expand Down
1 change: 1 addition & 0 deletions .tuist-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
4.133.1
65 changes: 65 additions & 0 deletions Sources/ISOInspectorApp/State/DocumentSessionController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
private var annotationsSelectionCancellable: AnyCancellable?
private var issueMetricsCancellable: AnyCancellable?
private var recentsChangeCancellable: AnyCancellable?
private var mirroredWindowSessionCancellables: Set<AnyCancellable> = []
private var latestSelectionNodeID: Int64?

// MARK: - Passthrough Properties
Expand Down Expand Up @@ -195,6 +196,25 @@
persistSession()
}

func synchronizeOpenedWindowSession(
recent: DocumentRecent, parseTreeStore sourceParseTreeStore: ParseTreeStore,
annotations sourceAnnotations: AnnotationBookmarkSession
) {
loadFailure = nil
recentsService.setLastFailedRecent(nil)
validationConfigurationService.updateActiveValidationConfiguration(for: recent)
applyValidationConfigurationFilter()
bindMirroredWindowSession(
parseTreeStore: sourceParseTreeStore, annotations: sourceAnnotations)

currentDocument = recent
recentsService.insertRecent(recent)
annotations.setFileURL(sourceAnnotations.currentFileURL ?? recent.url)
mirrorWindowParseState(from: sourceParseTreeStore)
documentViewModel.nodeViewModel.select(nodeID: sourceAnnotations.currentSelectedNodeID)
persistSession()
}

func removeRecent(at offsets: IndexSet) {
if recentsService.removeRecent(at: offsets) { persistSession() }
}
Expand Down Expand Up @@ -269,6 +289,51 @@
validationConfigurationService.sessionConfigurationsForPersistence())
}

private func bindMirroredWindowSession(
parseTreeStore sourceParseTreeStore: ParseTreeStore,
annotations sourceAnnotations: AnnotationBookmarkSession
) {
mirroredWindowSessionCancellables.removeAll()

sourceParseTreeStore.$snapshot.sink { [weak self, weak sourceParseTreeStore] _ in
guard let self, let sourceParseTreeStore else { return }
self.mirrorWindowParseState(from: sourceParseTreeStore)
}.store(in: &mirroredWindowSessionCancellables)

sourceParseTreeStore.$state.sink { [weak self, weak sourceParseTreeStore] _ in
guard let self, let sourceParseTreeStore else { return }
self.mirrorWindowParseState(from: sourceParseTreeStore)
}.store(in: &mirroredWindowSessionCancellables)

sourceParseTreeStore.$fileURL.sink { [weak self, weak sourceParseTreeStore] _ in
guard let self, let sourceParseTreeStore else { return }
self.mirrorWindowParseState(from: sourceParseTreeStore)
}.store(in: &mirroredWindowSessionCancellables)

sourceParseTreeStore.issueStore.$issues.receive(on: DispatchQueue.main).sink {
[weak self, weak sourceParseTreeStore] _ in
guard let self, let sourceParseTreeStore else { return }
self.mirrorWindowParseState(from: sourceParseTreeStore)
}.store(in: &mirroredWindowSessionCancellables)

sourceAnnotations.$currentFileURL.dropFirst().sink { [weak self] fileURL in
self?.annotations.setFileURL(fileURL)
}.store(in: &mirroredWindowSessionCancellables)

sourceAnnotations.$currentSelectedNodeID.dropFirst().sink { [weak self] nodeID in
guard let self else { return }
self.documentViewModel.nodeViewModel.select(nodeID: nodeID)
self.persistSession()
}.store(in: &mirroredWindowSessionCancellables)
}

private func mirrorWindowParseState(from sourceParseTreeStore: ParseTreeStore) {
parseTreeStore.replaceContents(
snapshot: sourceParseTreeStore.snapshot, state: sourceParseTreeStore.state,
fileURL: sourceParseTreeStore.fileURL,
issues: sourceParseTreeStore.issueStore.issuesSnapshot())
}

private func applyValidationConfigurationFilter() {
let configuration = validationConfiguration
let presets = validationPresets
Expand Down
13 changes: 13 additions & 0 deletions Sources/ISOInspectorApp/State/ParseTreeStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,19 @@
issueMetrics = issueStore.metricsSnapshot()
}

func replaceContents(
snapshot: ParseTreeSnapshot, state: ParseTreeStoreState, fileURL: URL?,
issues: [ParseIssue]
) {
disconnect()
builder = Self.makeBuilder(issueStore: issueStore)
issueStore.replaceAll(with: issues)
self.fileURL = fileURL?.standardizedFileURL
self.snapshot = Self.makeFilteredSnapshot(from: snapshot, filter: issueFilter)
self.state = state
self.issueMetrics = issueStore.metricsSnapshot()
}

private func disconnect() { resources.stop() }

private static func makeBuilder(issueStore: ParseIssueStore) -> Builder {
Expand Down
5 changes: 3 additions & 2 deletions Sources/ISOInspectorApp/State/WindowSessionController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,9 @@
displayName: url.lastPathComponent, lastOpened: Date())
currentDocument = recent

// Register with app controller's recent documents (without re-opening)
appSessionController.registerRecent(recent)
// Mirror the active window into the shared session without re-opening it.
appSessionController.synchronizeOpenedWindowSession(
recent: recent, parseTreeStore: parseTreeStore, annotations: annotations)
}
} catch {
await MainActor.run {
Expand Down
33 changes: 33 additions & 0 deletions Tests/ISOInspectorAppTests/DocumentSessionControllerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,39 @@
XCTAssertEqual(sessionStore.savedSnapshots.count, 1)
}

func testSynchronizeOpenedWindowSessionMirrorsWindowStateForSharedCommands() throws {
let recentsStore = DocumentRecentsStoreStub(initialRecents: [])
let sessionStore = WorkspaceSessionStoreStub()
let controller = makeController(store: recentsStore, sessionStore: sessionStore)
let windowParseTreeStore = ParseTreeStore()
let windowAnnotations = AnnotationBookmarkSession(store: nil)
let recent = sampleRecent(index: 1)

controller.synchronizeOpenedWindowSession(
recent: recent, parseTreeStore: windowParseTreeStore,
annotations: windowAnnotations)

XCTAssertEqual(
controller.currentDocument?.url.standardizedFileURL, recent.url.standardizedFileURL)
XCTAssertEqual(
controller.recents.first?.url.standardizedFileURL, recent.url.standardizedFileURL)
XCTAssertFalse(controller.documentViewModel.exportAvailability.canExportDocument)

let node = makeNode(identifier: 16, type: "moov")
let snapshot = ParseTreeSnapshot(nodes: [node], validationIssues: [])
windowParseTreeStore.replaceContents(
snapshot: snapshot, state: .finished, fileURL: recent.url, issues: [])
windowAnnotations.setSelectedNode(node.id)

XCTAssertEqual(controller.documentViewModel.snapshot, snapshot)
XCTAssertTrue(controller.documentViewModel.exportAvailability.canExportDocument)
XCTAssertEqual(controller.documentViewModel.nodeViewModel.selectedNodeID, node.id)
XCTAssertEqual(
sessionStore.savedSnapshots.last?.focusedFileURL?.standardizedFileURL,
recent.url.standardizedFileURL)
XCTAssertEqual(sessionStore.savedSnapshots.last?.files.first?.lastSelectionNodeID, node.id)
}

private func makeController(
store: DocumentRecentsStoring, sessionStore: WorkspaceSessionStoring? = nil,
annotationsStore: AnnotationBookmarkStoring? = nil, pipeline: ParsePipeline? = nil,
Expand Down
Loading