Skip to content

Commit

Permalink
terminal: custom font (closes #1037)
Browse files Browse the repository at this point in the history
  • Loading branch information
bummoblizard committed Jun 12, 2024
1 parent c8d3a5b commit fbd4b4a
Show file tree
Hide file tree
Showing 14 changed files with 115 additions and 41 deletions.
11 changes: 0 additions & 11 deletions CodeApp/CodeApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -281,17 +281,6 @@ struct CodeApp: App {
nil,
CFNotificationSuspensionBehavior.deliverImmediately)

// Disable mini map and line number for iPhones
if UIScreen.main.traitCollection.horizontalSizeClass == .compact {
if UserDefaults.standard.object(forKey: "editorLineNumberEnabled") == nil {
UserDefaults.standard.setValue(false, forKey: "editorLineNumberEnabled")
UserDefaults.standard.setValue(false, forKey: "editorMiniMapEnabled")
}
if UserDefaults.standard.object(forKey: "compilerShowPath") == nil {
UserDefaults.standard.setValue(false, forKey: "compilerShowPath")
}
}

if versionNumberIncreased() || needToUpdateCFiles() {
createCSDK()
}
Expand Down
5 changes: 5 additions & 0 deletions CodeApp/Containers/MainScene.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ private struct MainView: View {

@AppStorage("changelog.lastread") var changeLogLastReadVersion = "0.0"
@AppStorage("runeStoneEditorEnabled") var runeStoneEditorEnabled: Bool = false
@AppStorage("terminalOptions") var terminalOptions: CodableWrapper<TerminalOptions> = .init(
value: TerminalOptions())

@SceneStorage("sidebar.visible") var isSideBarVisible: Bool = DefaultUIState.SIDEBAR_VISIBLE
@SceneStorage("panel.height") var panelHeight: Double = DefaultUIState.PANEL_HEIGHT
Expand Down Expand Up @@ -232,6 +234,9 @@ private struct MainView: View {
.onChange(of: runeStoneEditorEnabled) { _ in
App.setUpEditorInstance()
}
.onChange(of: terminalOptions) { newValue in
App.terminalInstance.options = newValue.value
}
.hiddenScrollableContentBackground()
.onAppear {
let appVersion =
Expand Down
2 changes: 2 additions & 0 deletions CodeApp/Localization/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@
"settings.explorer.show_hidden_files" = "Versteckte Dateien anzeigen";
"settings.runestone.editor" = "Runestone Editor";
"settings.runestone.editor.notes" = "Runestone ist ein Editor mit nativer Textauswahlunterstützung. Einige Funktionen sind in diesem Modus nicht verfügbar.";
"settings.terminal.font" = "Schriftart";

"panels.no_panel_selected" = "Kein Panel ausgewählt";
"sidebar.no_section_selected" = "Kein Abschnitt ausgewählt";

Expand Down
2 changes: 2 additions & 0 deletions CodeApp/Localization/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ are licensed under [BSD-3-Clause License](https://en.wikipedia.org/wiki/BSD_lice
"settings.explorer.show_hidden_files" = "Show Hidden Files";
"settings.runestone.editor" = "Runestone Editor";
"settings.runestone.editor.notes" = "Runestone is an editor with native text selection support. Some features are unavailable in this mode.";
"settings.terminal.font" = "Font";

"panels.no_panel_selected" = "No panel selected";
"sidebar.no_section_selected" = "No section selected.";

Expand Down
2 changes: 2 additions & 0 deletions CodeApp/Localization/ja.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,8 @@
"settings.explorer.show_hidden_files" = "隠しファイルを表示";
"settings.runestone.editor" = "Runestoneエディタ";
"settings.runestone.editor.notes" = "Runestone はネイティブのテキスト選択をサポートするエディターです。このモードでは一部の機能は使用できません。";
"settings.terminal.font" = "フォント";

"panels.no_panel_selected" = "パネルが選択されていません";
"sidebar.no_section_selected" = "セクションが選択されていません";

Expand Down
2 changes: 2 additions & 0 deletions CodeApp/Localization/ko.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,8 @@
"settings.explorer.show_hidden_files" = "숨김 파일 표시";
"settings.runestone.editor" = "Runestone 편집기";
"settings.runestone.editor.notes" = "Runestone은 기본 텍스트 선택을 지원하는 편집기입니다. 이 모드에서는 일부 기능을 사용할 수 없습니다.";
"settings.terminal.font" = "글꼴";

"panels.no_panel_selected" = "패널이 선택되지 않았습니다.";
"sidebar.no_section_selected" = "섹션이 선택되지 않았습니다.";

Expand Down
2 changes: 2 additions & 0 deletions CodeApp/Localization/zh-Hans.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,8 @@
"settings.explorer.show_hidden_files" = "显示隐藏文件";
"settings.runestone.editor" = "Runestone编辑器";
"settings.runestone.editor.notes" = "Runestone是一款具有本地文本选择支持的编辑器。在此模式下,某些功能无法使用。";
"settings.terminal.font" = "字体";

"panels.no_panel_selected" = "没有选中的面板";
"sidebar.no_section_selected" = "没有选中的版面";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ struct EditorOptions: Codable {
var toolBarEnabled: Bool
var vimEnabled: Bool

// subsequent options must be made optional

init() {
self.fontSize = 14
self.fontFamily = "Menlo"
Expand Down
9 changes: 4 additions & 5 deletions CodeApp/Managers/MainApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ class MainApp: ObservableObject {
var editorShortcuts: [MonacoEditorAction] = []
var monacoStateToRestore: String? = nil

let terminalInstance: TerminalInstance
var terminalInstance: TerminalInstance! = nil
var monacoInstance: EditorImplementation! = nil
var editorTypesMonitor: FolderMonitor? = nil
let deviceSupportsBiometricAuth: Bool = biometricAuthSupported()
Expand All @@ -156,12 +156,11 @@ class MainApp: ObservableObject {
private var workSpaceCancellable: AnyCancellable? = nil

@AppStorage("alwaysOpenInNewTab") var alwaysOpenInNewTab: Bool = false
@AppStorage("compilerShowPath") var compilerShowPath = false
@AppStorage("editorSpellCheckEnabled") var editorSpellCheckEnabled = false
@AppStorage("editorSpellCheckOnContentChanged") var editorSpellCheckOnContentChanged = true
@AppStorage("explorer.confirmBeforeDelete") var confirmBeforeDelete = false
@AppStorage("editorOptions") var editorOptions: CodableWrapper<EditorOptions> = .init(
value: EditorOptions())
@AppStorage("terminalOptions") var terminalOptions: CodableWrapper<TerminalOptions> = .init(
value: TerminalOptions())
@AppStorage("editorLightTheme") var selectedLightTheme: String = "Light+"
@AppStorage("editorDarkTheme") var selectedTheme: String = "Dark+"
@AppStorage("stateRestorationEnabled") var stateRestorationEnabled = true
Expand All @@ -173,7 +172,7 @@ class MainApp: ObservableObject {

self.workSpaceStorage = WorkSpaceStorage(url: rootDir)

terminalInstance = TerminalInstance(root: rootDir)
terminalInstance = TerminalInstance(root: rootDir, options: terminalOptions.value)
setUpEditorInstance()

terminalInstance.openEditor = { [weak self] url in
Expand Down
52 changes: 46 additions & 6 deletions CodeApp/Managers/TerminalInstance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,23 @@ import SwiftUI
import WebKit
import ios_system

struct TerminalOptions: Codable {
var fontSize: Int = 14
var fontFamily: String = "Menlo"
var toolbarEnabled: Bool = true
var shouldShowCompilerPath: Bool = false

// subsequent options must be made optional
}

class TerminalInstance: NSObject, WKScriptMessageHandler, WKNavigationDelegate {

var options: TerminalOptions {
didSet {
configureCustomOptions()
}
}

let INTERRUPT = "\u{03}"
let END_OF_TRANSMISSION = "\u{04}"

Expand Down Expand Up @@ -59,6 +74,34 @@ class TerminalInstance: NSObject, WKScriptMessageHandler, WKNavigationDelegate {
executeScript("term.options.fontSize = \(size)")
}

private func applyFont(fontFamily: String) {
guard
let percentEncoded = fontFamily.addingPercentEncoding(
withAllowedCharacters: .urlPathAllowed)
else {
return
}
let js = """
var styles = `
@font-face {
font-family: "\(fontFamily)";
src: local("\(fontFamily)"),
url("fonts://\(percentEncoded).ttf") format("truetype");
}
`
var styleSheet = document.createElement("style")
styleSheet.innerHTML = styles
document.head.appendChild(styleSheet)
"""
executeScript(js)
executeScript("term.options.fontFamily = '\(fontFamily)'")
}

private func configureCustomOptions() {
executeScript("term.options.fontSize = \(String(options.fontSize))")
applyFont(fontFamily: options.fontFamily)
}

func resetAndSetNewRootDirectory(url: URL) {
executor?.setNewWorkingDirectory(url: url)
guard let prompt = executor?.prompt else {
Expand Down Expand Up @@ -306,11 +349,7 @@ class TerminalInstance: NSObject, WKScriptMessageHandler, WKNavigationDelegate {
if globalDarkTheme != nil {
self.applyTheme(rawTheme: globalDarkTheme!)
}

let fontSize = UserDefaults.standard.integer(forKey: "consoleFontSize")
if fontSize != 0 {
self.setFontSize(size: fontSize)
}
configureCustomOptions()
case "window.size.change":
let cols = result["Cols"] as! Int
let rows = result["Rows"] as! Int
Expand Down Expand Up @@ -354,7 +393,8 @@ class TerminalInstance: NSObject, WKScriptMessageHandler, WKNavigationDelegate {
}
}

init(root: URL) {
init(root: URL, options: TerminalOptions) {
self.options = options
super.init()
self.executor = Executor(
root: root,
Expand Down
2 changes: 1 addition & 1 deletion CodeApp/Views/SettingsFontPicker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import UIKit
public struct SettingsFontPicker: UIViewControllerRepresentable {

@Environment(\.presentationMode) var presentationMode
@State var showAllFonts: Bool
@Binding var showAllFonts: Bool
var onFontPick: (UIFontDescriptor) -> Void

public func makeUIViewController(
Expand Down
54 changes: 44 additions & 10 deletions CodeApp/Views/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,20 @@ struct SettingsView: View {

@AppStorage("suggestionEnabled") var suggestionEnabled: Bool = true
@AppStorage("editorShowKeyboardButtonEnabled") var editorShowKeyboardButtonEnabled: Bool = true
@AppStorage("consoleFontSize") var consoleFontSize: Int = 14
@AppStorage("terminalToolBarEnabled") var terminalToolBarEnabled: Bool = true
@AppStorage("preferredColorScheme") var preferredColorScheme: Int = 0
@AppStorage("explorer.showHiddenFiles") var showHiddenFiles: Bool = false
@AppStorage("explorer.confirmBeforeDelete") var confirmBeforeDelete = false
@AppStorage("alwaysOpenInNewTab") var alwaysOpenInNewTab: Bool = false
@AppStorage("stateRestorationEnabled") var stateRestorationEnabled = true
@AppStorage("compilerShowPath") var compilerShowPath = false
@AppStorage("communityTemplatesEnabled") var communityTemplatesEnabled = true
@AppStorage("showAllFonts") var showAllFonts = false
@AppStorage("remoteShouldResolveHomePath") var remoteShouldResolveHomePath = false
@AppStorage("editorOptions") var editorOptions: CodableWrapper<EditorOptions> = .init(
value: EditorOptions())
@AppStorage("terminalOptions") var terminalOptions: CodableWrapper<TerminalOptions> = .init(
value: TerminalOptions())
@AppStorage("runeStoneEditorEnabled") var runeStoneEditorEnabled: Bool = false

@State var showAllFonts = false
@State var showsEraseAlert: Bool = false
@State var showReceiptInformation: Bool = false

Expand Down Expand Up @@ -65,8 +64,8 @@ struct SettingsView: View {
)

Stepper(
"\(NSLocalizedString("Console Font Size", comment: "")) (\(consoleFontSize))",
value: $consoleFontSize, in: 8...24)
"\(NSLocalizedString("Console Font Size", comment: "")) (\(terminalOptions.value.fontSize))",
value: $terminalOptions.value.fontSize, in: 8...24)

Button(action: {
guard let url = URL(string: "https://github.com/thebaselab/codeapp")
Expand Down Expand Up @@ -125,14 +124,18 @@ struct SettingsView: View {

NavigationLink(
destination: SettingsFontPicker(
showAllFonts: showAllFonts,
showAllFonts: $showAllFonts,
onFontPick: { descriptor in
CTFontManagerRequestFonts([descriptor] as CFArray) { _ in
editorOptions.value.fontFamily =
descriptor.object(forKey: .family) as! String
}
}
).toolbar {
Button("Show all fonts") {
showAllFonts.toggle()
}

Button("settings.editor.font.reset") {
editorOptions.value.fontFamily = "Menlo"
}
Expand Down Expand Up @@ -237,10 +240,41 @@ struct SettingsView: View {
footer: { Text("settings.runestone.editor.notes") })

Section(header: Text("TERMINAL")) {
NavigationLink(
destination: SettingsFontPicker(
showAllFonts: $showAllFonts,
onFontPick: { descriptor in
CTFontManagerRequestFonts([descriptor] as CFArray) { _ in
terminalOptions.value.fontFamily =
descriptor.object(forKey: .family) as! String
}
}
).toolbar {
Button("Show all fonts") {
showAllFonts.toggle()
}

Button("settings.editor.font.reset") {
terminalOptions.value.fontFamily = TerminalOptions().fontFamily
}
.disabled(
terminalOptions.value.fontFamily == TerminalOptions().fontFamily
)
},
label: {
HStack {
Text("settings.terminal.font")
Spacer()
Text(terminalOptions.value.fontFamily)
.foregroundColor(.gray)
}
}
)

Toggle("Keyboard Toolbar", isOn: $terminalOptions.value.toolbarEnabled)
Toggle(
"Keyboard Toolbar",
isOn: $terminalToolBarEnabled)
Toggle("Show Command in Terminal", isOn: $compilerShowPath)
"Show Command in Terminal",
isOn: $terminalOptions.value.shouldShowCompilerPath)
}

Section(header: Text(NSLocalizedString("About", comment: ""))) {
Expand Down
3 changes: 1 addition & 2 deletions Extensions/LocalExecution/LocalExecutionExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ class LocalExecutionExtension: CodeAppExtension {
with: lastPathComponentWithoutExtension)
}

let compilerShowPath = UserDefaults.standard.bool(forKey: "compilerShowPath")
if compilerShowPath {
if app.terminalOptions.value.shouldShowCompilerPath {
app.terminalInstance.executeScript(
"localEcho.println(`\(parsedCommands.joined(separator: " && "))`);readLine('');")
} else {
Expand Down
8 changes: 2 additions & 6 deletions Extensions/TerminalService/TerminalExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ private struct _TerminalView: UIViewRepresentable {
var implementation: TerminalInstance

@EnvironmentObject var App: MainApp
@AppStorage("terminalToolBarEnabled") var terminalToolBarEnabled: Bool = true

private func injectBarButtons(webView: WebViewBase) {
let toolbar = UIHostingController(
Expand All @@ -64,14 +63,14 @@ private struct _TerminalView: UIViewRepresentable {
}

func makeUIView(context: Context) -> UIView {
if terminalToolBarEnabled {
if implementation.options.toolbarEnabled {
injectBarButtons(webView: implementation.webView)
}
return implementation.webView
}

func updateUIView(_ uiView: UIView, context: Context) {
if terminalToolBarEnabled {
if implementation.options.toolbarEnabled {
injectBarButtons(webView: implementation.webView)
} else {
removeBarButtons(webView: implementation.webView)
Expand Down Expand Up @@ -122,8 +121,5 @@ private struct TerminalView: View {
})
}
.foregroundColor(.clear)
.onChange(of: consoleFontSize) { value in
App.terminalInstance.setFontSize(size: value)
}
}
}

0 comments on commit fbd4b4a

Please sign in to comment.