Skip to content

Commit beee1a1

Browse files
committed
Environment: x86 virtualization path + SDK distro/arch gating
SDK Manager - SdkCatalogEntry gains supportedDistros/supportedArches + isSupportedOn(); the manager hides entries unsupported on the active distro/arch, and the service rejects unsupported actions at execution time. - New Virtualization category + qemu-system-x86 entry (full-system QEMU to run x86 VMs on ARM, since SQL Server's engine segfaults under user-mode emulation). Environment - Remove the x86_64 (amd64) distro and the bundled user-mode qemu asset; back to ARM64-only Ubuntu 24.04 / 26.04. - Drop Box64 references (the extension is removed from the marketplace). Also lands accumulated workbench features on this branch: session restore, per-extension activation modes, and the extension web-UI platform (WebView host + JCode bridge driving the Linux runtime).
1 parent c348e9e commit beee1a1

26 files changed

Lines changed: 1372 additions & 42 deletions

File tree

app/src/main/java/dev/jcode/JCodeShell.kt

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import dev.jcode.editor.languagePackCompletionItems
1111
import dev.jcode.design.LocalEditorSaveActions
1212
import dev.jcode.design.JCodeIcon
1313
import dev.jcode.design.JcTooltip
14+
import dev.jcode.design.EditorDragSetting
15+
import dev.jcode.design.LocalEditorDragMovesCursor
16+
import dev.jcode.design.LocalRestoreSession
1417
import dev.jcode.design.LocalTabCloseButtonSetting
18+
import dev.jcode.design.RestoreSessionSetting
1519
import dev.jcode.design.TabCloseButtonSetting
1620
import dev.jcode.editor.SyntaxHighlighter
1721
import dev.jcode.editor.TokenPalette
@@ -200,7 +204,13 @@ import dev.jcode.feature.sdkmanager.SdkManagerFeature
200204
import dev.jcode.feature.settings.SettingsFeature
201205
import dev.jcode.workbench.dialog.NewItemDialog
202206
import dev.jcode.workbench.dialog.OpenFolderTypeDialog
207+
import dev.jcode.feature.marketplace.ExtensionActivation
208+
import dev.jcode.workbench.marketplace.ExtensionActivationSetting
209+
import dev.jcode.workbench.ExtensionWebViewPage
210+
import dev.jcode.workbench.marketplace.DbManagerPanel
203211
import dev.jcode.workbench.marketplace.ExtensionDetailPage
212+
import dev.jcode.workbench.marketplace.ExtensionPermissionsPage
213+
import dev.jcode.workbench.marketplace.LocalExtensionActivation
204214
import dev.jcode.workbench.marketplace.ExtensionsPanel
205215
import dev.jcode.workbench.LocalTerminalTapConfig
206216
import dev.jcode.workbench.RightPanelTab
@@ -253,6 +263,16 @@ fun JCodeApp(
253263
val runConfigVersion by viewModel.runConfigVersion.collectAsStateWithLifecycle()
254264
val autoSetupProgress by viewModel.autoSetupProgress.collectAsStateWithLifecycle(initialValue = DistroWizardProgress.Idle)
255265
val installedExtensions by viewModel.installedExtensions.collectAsStateWithLifecycle()
266+
// Extensions whose contributions are active (not set to Manual) — used for all language-pack lookups
267+
// so the per-extension activation mode actually gates highlighting/completions/formatting.
268+
val activeLanguageExtensions by viewModel.activeLanguageExtensions.collectAsStateWithLifecycle()
269+
val extensionActivations by viewModel.extensionActivations.collectAsStateWithLifecycle()
270+
val extensionActivationSetting = remember(extensionActivations) {
271+
ExtensionActivationSetting(
272+
modeFor = { id -> extensionActivations[id] ?: ExtensionActivation.Default },
273+
onChange = viewModel::setExtensionActivation,
274+
)
275+
}
256276
val marketplaceEntries by viewModel.marketplaceEntries.collectAsStateWithLifecycle()
257277
val marketplaceBusy by viewModel.marketplaceBusy.collectAsStateWithLifecycle()
258278
val themeMode by viewModel.themeMode.collectAsStateWithLifecycle()
@@ -267,6 +287,23 @@ fun JCodeApp(
267287
val tabCloseSetting = remember(hideTabCloseButton) {
268288
TabCloseButtonSetting(hideTabCloseButton, viewModel::setHideTabCloseButton)
269289
}
290+
val editorDragMovesCursor by viewModel.editorDragMovesCursor.collectAsStateWithLifecycle()
291+
val cursorDragVerticalLevel by viewModel.editorCursorDragVerticalLevel.collectAsStateWithLifecycle()
292+
val cursorDragHorizontalLevel by viewModel.editorCursorDragHorizontalLevel.collectAsStateWithLifecycle()
293+
val editorDragSetting = remember(editorDragMovesCursor, cursorDragVerticalLevel, cursorDragHorizontalLevel) {
294+
EditorDragSetting(
295+
enabled = editorDragMovesCursor,
296+
onChange = viewModel::setEditorDragMovesCursor,
297+
verticalLevel = cursorDragVerticalLevel,
298+
horizontalLevel = cursorDragHorizontalLevel,
299+
onVerticalLevelChange = viewModel::setEditorCursorDragVerticalLevel,
300+
onHorizontalLevelChange = viewModel::setEditorCursorDragHorizontalLevel,
301+
)
302+
}
303+
val restoreLastSession by viewModel.restoreLastSession.collectAsStateWithLifecycle()
304+
val restoreSessionSetting = remember(restoreLastSession) {
305+
RestoreSessionSetting(restoreLastSession, viewModel::setRestoreLastSession)
306+
}
270307
val editorSaveActions = remember(viewModel) {
271308
EditorSaveActions(
272309
onUndo = viewModel::undoActiveTab,
@@ -278,8 +315,8 @@ fun JCodeApp(
278315
}
279316
// Completion items for the focused file, resolved from its installed language pack (if any).
280317
val activeFileName = editorGroup.activeTab?.filePath?.name
281-
val activeLanguagePack = remember(activeFileName, installedExtensions) {
282-
activeFileName?.let { n -> installedExtensions.firstNotNullOfOrNull { it.languageFor(n) } }
318+
val activeLanguagePack = remember(activeFileName, activeLanguageExtensions) {
319+
activeFileName?.let { n -> activeLanguageExtensions.firstNotNullOfOrNull { it.languageFor(n) } }
283320
}
284321
val completionSource = remember(activeLanguagePack) {
285322
{ prefix: String -> languagePackCompletionItems(activeLanguagePack, prefix) }
@@ -355,6 +392,9 @@ fun JCodeApp(
355392
CompositionLocalProvider(
356393
LocalTerminalTapConfig provides terminalTapConfig,
357394
LocalTabCloseButtonSetting provides tabCloseSetting,
395+
LocalEditorDragMovesCursor provides editorDragSetting,
396+
LocalRestoreSession provides restoreSessionSetting,
397+
LocalExtensionActivation provides extensionActivationSetting,
358398
LocalEditorSaveActions provides editorSaveActions,
359399
LocalCompletionSource provides completionSource,
360400
LocalEnvironmentManager provides environmentManagerActions,
@@ -431,6 +471,9 @@ fun JCodeApp(
431471
onInstallExtension = viewModel::installExtension,
432472
onUninstallExtension = viewModel::uninstallExtension,
433473
onOpenExtensionDetail = viewModel::openExtensionDetailPage,
474+
onOpenExtensionPermissions = viewModel::openExtensionPermissionsPage,
475+
onOpenExtensionApp = viewModel::openExtensionAppPage,
476+
onExtensionExec = viewModel::runtimeExecJson,
434477
),
435478
onOpenSettingsPage = viewModel::openSettingsPage,
436479
terminalDoubleTapToFocus = terminalDoubleTapToFocus,
@@ -569,11 +612,15 @@ private fun JCodeShell(
569612
ThemeMode.Light -> false
570613
ThemeMode.System -> systemDark
571614
}
615+
// Only extensions not set to Manual contribute language features (highlighting/completions/format).
616+
val activeLanguageExtensions = installedExtensions.filter {
617+
LocalExtensionActivation.current.modeFor(it.id) != ExtensionActivation.Manual
618+
}
572619
val highlightTab = editorGroup.activeTab
573-
LaunchedEffect(highlightTab?.id, installedExtensions, editorDark) {
620+
LaunchedEffect(highlightTab?.id, activeLanguageExtensions, editorDark) {
574621
val state = highlightTab?.editorState ?: return@LaunchedEffect
575622
val fileName = highlightTab.filePath.name
576-
val lang = installedExtensions.firstNotNullOfOrNull { ext -> ext.languageFor(fileName) }
623+
val lang = activeLanguageExtensions.firstNotNullOfOrNull { ext -> ext.languageFor(fileName) }
577624
val palette = if (editorDark) TokenPalette.DARK else TokenPalette.LIGHT
578625
state.snapshot.collectLatest { snap ->
579626
val spans = withContext(Dispatchers.Default) {
@@ -1142,7 +1189,7 @@ private fun JCodeShell(
11421189
},
11431190
languageActionsEnabled = run {
11441191
val name = editorGroup.activeTab?.filePath?.name
1145-
name != null && installedExtensions.any { it.languageFor(name) != null }
1192+
name != null && activeLanguageExtensions.any { it.languageFor(name) != null }
11461193
},
11471194
onEditorLanguageAction = { action, word ->
11481195
if (action == EditorLanguageAction.FormatDocument) {
@@ -1258,10 +1305,28 @@ private fun JCodeShell(
12581305
busy = marketplaceBusy,
12591306
onInstall = managerActions.onInstallExtension,
12601307
onUninstall = managerActions.onUninstallExtension,
1308+
onOpenApp = managerActions.onOpenExtensionApp,
12611309
modifier = Modifier.fillMaxSize(),
12621310
)
12631311
}
12641312
}
1313+
EditorPageKind.ExtensionPermissions -> ExtensionPermissionsPage(
1314+
installed = installedExtensions,
1315+
modifier = Modifier.fillMaxSize(),
1316+
)
1317+
EditorPageKind.ExtensionApp -> {
1318+
val appId = tab.id.substringAfter(MainViewModel.EXT_APP_PREFIX)
1319+
installedExtensions.firstOrNull { it.id == appId }?.let { ext ->
1320+
// Key by id so each extension app gets its own WebView (no reuse across tabs).
1321+
key(ext.id) {
1322+
ExtensionWebViewPage(
1323+
extension = ext,
1324+
onExec = managerActions.onExtensionExec,
1325+
modifier = Modifier.fillMaxSize(),
1326+
)
1327+
}
1328+
}
1329+
}
12651330
EditorPageKind.None -> Unit
12661331
}
12671332
},
@@ -1683,6 +1748,7 @@ private fun WorkspacePanel(
16831748
busy = marketplaceBusy,
16841749
onRefreshMarketplace = managerActions.onRefreshMarketplace,
16851750
onOpenDetail = managerActions.onOpenExtensionDetail,
1751+
onOpenPermissions = managerActions.onOpenExtensionPermissions,
16861752
modifier = Modifier.fillMaxSize(),
16871753
)
16881754

@@ -1702,6 +1768,12 @@ private fun WorkspacePanel(
17021768
modifier = Modifier.fillMaxSize(),
17031769
)
17041770

1771+
WorkbenchTool.DbManager -> DbManagerPanel(
1772+
installed = installedExtensions,
1773+
onOpenApp = managerActions.onOpenExtensionApp,
1774+
modifier = Modifier.fillMaxSize(),
1775+
)
1776+
17051777
// Settings opens as an in-editor page (see EditorWorkspace); it is never the
17061778
// selected side-panel tool, so this branch renders nothing.
17071779
WorkbenchTool.Settings -> Unit

app/src/main/java/dev/jcode/MainActivity.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ class MainActivity : ComponentActivity() {
3737
viewModel.refreshEnvironment()
3838
}
3939

40+
override fun onStop() {
41+
super.onStop()
42+
// Capture the latest workbench state when backgrounded, in case the process is killed next.
43+
viewModel.flushSessionNow()
44+
}
45+
4046
fun openPermissionSettings() {
4147
Log.d(TAG, "Opening permission settings")
4248
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {

0 commit comments

Comments
 (0)