mirror of
https://github.com/h3pdesign/Neon-Vision-Editor
synced 2026-04-21 13:27:16 +00:00
Add TeX language support and improve code snapshot UX
This commit is contained in:
parent
94537eaa21
commit
aa23871125
12 changed files with 216 additions and 16 deletions
|
|
@ -361,7 +361,7 @@
|
|||
CODE_SIGNING_ALLOWED = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 520;
|
||||
CURRENT_PROJECT_VERSION = 521;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = CS727NF72U;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
|
|
@ -444,7 +444,7 @@
|
|||
CODE_SIGNING_ALLOWED = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 520;
|
||||
CURRENT_PROJECT_VERSION = 521;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = CS727NF72U;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ struct NeonVisionMacAppCommands: Commands {
|
|||
"swift", "python", "javascript", "typescript", "php", "java", "kotlin", "go", "ruby",
|
||||
"rust", "cobol", "dotenv", "proto", "graphql", "rst", "nginx", "sql", "html",
|
||||
"expressionengine", "css", "c", "cpp", "csharp", "objective-c", "json", "xml", "yaml",
|
||||
"toml", "csv", "ini", "vim", "log", "ipynb", "markdown", "bash", "zsh", "powershell",
|
||||
"toml", "csv", "ini", "vim", "log", "ipynb", "markdown", "tex", "bash", "zsh", "powershell",
|
||||
"standard", "plain"
|
||||
]
|
||||
|
||||
|
|
@ -468,6 +468,7 @@ struct NeonVisionMacAppCommands: Commands {
|
|||
case "vim": return "Vim"
|
||||
case "log": return "Log"
|
||||
case "ipynb": return "Jupyter Notebook"
|
||||
case "tex": return "TeX"
|
||||
case "html": return "HTML"
|
||||
case "expressionengine": return "ExpressionEngine"
|
||||
case "css": return "CSS"
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ enum CompletionHeuristics {
|
|||
"typescript": ["async", "await", "break", "case", "catch", "class", "const", "continue", "default", "else", "enum", "export", "extends", "false", "finally", "for", "function", "if", "implements", "import", "in", "interface", "let", "namespace", "new", "null", "private", "protected", "public", "readonly", "return", "switch", "this", "throw", "true", "try", "type", "var", "while"],
|
||||
"json": ["false", "null", "true"],
|
||||
"markdown": ["```", "###", "##", "#", "- ", "1. ", "> "],
|
||||
"tex": ["\\begin{}", "\\end{}", "\\section{}", "\\subsection{}", "\\textbf{}", "\\emph{}", "\\item", "\\cite{}", "\\label{}", "\\ref{}"],
|
||||
"plain": []
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,11 @@ public struct LanguageDetector {
|
|||
"json5": "json",
|
||||
"md": "markdown",
|
||||
"markdown": "markdown",
|
||||
"tex": "tex",
|
||||
"latex": "tex",
|
||||
"bib": "tex",
|
||||
"sty": "tex",
|
||||
"cls": "tex",
|
||||
"env": "dotenv",
|
||||
"proto": "proto",
|
||||
"graphql": "graphql",
|
||||
|
|
@ -123,7 +128,7 @@ public struct LanguageDetector {
|
|||
"swift", "csharp", "php", "csv", "python", "javascript", "typescript", "java", "kotlin",
|
||||
"go", "ruby", "rust", "dotenv", "proto", "graphql", "rst", "nginx", "cpp", "c",
|
||||
"css", "markdown", "json", "html", "expressionengine", "sql", "xml", "yaml", "toml", "ini", "vim",
|
||||
"log", "ipynb", "powershell", "cobol", "objective-c", "bash", "zsh"
|
||||
"log", "ipynb", "powershell", "cobol", "objective-c", "bash", "zsh", "tex"
|
||||
]
|
||||
for lang in languages { scores[lang] = 0 }
|
||||
|
||||
|
|
@ -208,6 +213,14 @@ public struct LanguageDetector {
|
|||
bump("zsh", -40)
|
||||
}
|
||||
|
||||
// TeX / LaTeX
|
||||
if regexBool(lower, pattern: #"\\documentclass(\[[^\]]*\])?\{[^}]+\}"#) { bump("tex", 240) }
|
||||
if regexBool(lower, pattern: #"\\usepackage(\[[^\]]*\])?\{[^}]+\}"#) { bump("tex", 180) }
|
||||
if regexBool(lower, pattern: #"\\begin\{document\}|\\end\{document\}"#) { bump("tex", 220) }
|
||||
if regexBool(lower, pattern: #"\\begin\{[A-Za-z*]+\}|\\end\{[A-Za-z*]+\}"#) { bump("tex", 90) }
|
||||
if regexBool(lower, pattern: #"\\(section|subsection|chapter|paragraph)\*?\{[^}]+\}"#) { bump("tex", 80) }
|
||||
if regexBool(lower, pattern: #"\\cite\{[^}]+\}|\\bibliography\{[^}]+\}"#) { bump("tex", 70) }
|
||||
|
||||
let dotenvCount = regexCount(lower, pattern: "(?m)^[A-Za-z_][A-Za-z0-9_]*=.+$")
|
||||
if dotenvCount > 0 && tomlSectionCount == 0 {
|
||||
bump("dotenv", min(220, dotenvCount * 30))
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ func getSyntaxPatterns(
|
|||
canonical = "typescript"
|
||||
case "ee", "expression-engine", "expression_engine":
|
||||
canonical = "expressionengine"
|
||||
case "latex", "bibtex":
|
||||
canonical = "tex"
|
||||
default:
|
||||
canonical = normalized
|
||||
}
|
||||
|
|
@ -249,6 +251,16 @@ func getSyntaxPatterns(
|
|||
#"\[[^\]]+\]\([^)]+\)"#: colors.string,
|
||||
#"(?m)^>\s+.*$"#: colors.comment
|
||||
]
|
||||
case "tex":
|
||||
return [
|
||||
#"\\[A-Za-z@]+(\*?)"#: colors.keyword,
|
||||
#"\\begin\{[^}]+\}|\\end\{[^}]+\}"#: colors.meta,
|
||||
#"\{[^{}\n]*\}"#: colors.property,
|
||||
#"\[[^\]\n]*\]"#: colors.attribute,
|
||||
#"\$[^$\n]+\$|\$\$[\s\S]*?\$\$"#: colors.string,
|
||||
#"(?m)%.*$"#: colors.comment,
|
||||
#"\b[0-9]+(\.[0-9]+)?\b"#: colors.number
|
||||
]
|
||||
case "bash":
|
||||
return [
|
||||
// Keywords and flow control
|
||||
|
|
|
|||
|
|
@ -912,6 +912,11 @@ class EditorViewModel {
|
|||
"json5": "json",
|
||||
"md": "markdown",
|
||||
"markdown": "markdown",
|
||||
"tex": "tex",
|
||||
"latex": "tex",
|
||||
"bib": "tex",
|
||||
"sty": "tex",
|
||||
"cls": "tex",
|
||||
"env": "dotenv",
|
||||
"proto": "proto",
|
||||
"graphql": "graphql",
|
||||
|
|
@ -1337,7 +1342,8 @@ class EditorViewModel {
|
|||
"log", "vim", "ipynb", "java", "kt", "kts", "go", "rb", "rs", "ps1", "psm1",
|
||||
"html", "htm", "ee", "exp", "tmpl", "css", "c", "cpp", "cc", "hpp", "hh", "h",
|
||||
"m", "mm", "cs", "json", "jsonc", "json5", "md", "markdown", "env", "proto",
|
||||
"graphql", "gql", "rst", "conf", "nginx", "cob", "cbl", "cobol", "sh", "bash", "zsh"
|
||||
"graphql", "gql", "rst", "conf", "nginx", "cob", "cbl", "cobol", "sh", "bash", "zsh",
|
||||
"tex", "latex", "bib", "sty", "cls"
|
||||
]
|
||||
if knownSupportedExtensions.contains(ext) {
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -315,6 +315,9 @@ struct CodeSnapshotComposerView: View {
|
|||
let payload: CodeSnapshotPayload
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
#if os(iOS)
|
||||
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
|
||||
#endif
|
||||
@State private var style = CodeSnapshotStyle()
|
||||
@State private var renderedPNGData: Data?
|
||||
@State private var shareURL: URL?
|
||||
|
|
@ -322,16 +325,33 @@ struct CodeSnapshotComposerView: View {
|
|||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
VStack(spacing: 20) {
|
||||
snapshotControls
|
||||
ScrollView([.vertical, .horizontal]) {
|
||||
CodeSnapshotCardView(payload: payload, style: style)
|
||||
.frame(maxWidth: 980)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.bottom, 20)
|
||||
GeometryReader { proxy in
|
||||
let availableWidth = max(320, proxy.size.width - 40)
|
||||
let estimatedControlsHeight: CGFloat = usesCompactScrollingLayout ? 180 : 132
|
||||
let availablePreviewHeight = max(220, proxy.size.height - estimatedControlsHeight - 44)
|
||||
let fittedPreviewWidth = min(980, availableWidth, availablePreviewHeight * 1.25)
|
||||
|
||||
VStack(spacing: 16) {
|
||||
snapshotControls
|
||||
Group {
|
||||
if usesCompactScrollingLayout {
|
||||
ScrollView([.vertical, .horizontal]) {
|
||||
CodeSnapshotCardView(payload: payload, style: style)
|
||||
.frame(width: min(980, availableWidth))
|
||||
.padding(.bottom, 20)
|
||||
}
|
||||
} else {
|
||||
CodeSnapshotCardView(payload: payload, style: style)
|
||||
.frame(width: fittedPreviewWidth)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.top, 20)
|
||||
.padding(.bottom, 12)
|
||||
}
|
||||
.padding(20)
|
||||
.navigationTitle("Code Snapshot")
|
||||
#if os(iOS)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
|
|
@ -355,6 +375,9 @@ struct CodeSnapshotComposerView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
#if os(macOS)
|
||||
.frame(minWidth: 1020, minHeight: 760)
|
||||
#endif
|
||||
.task(id: style) {
|
||||
await refreshRenderedSnapshot()
|
||||
}
|
||||
|
|
@ -366,8 +389,77 @@ struct CodeSnapshotComposerView: View {
|
|||
) { _ in }
|
||||
}
|
||||
|
||||
private var usesCompactScrollingLayout: Bool {
|
||||
#if os(iOS)
|
||||
return horizontalSizeClass == .compact
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
|
||||
private var snapshotControls: some View {
|
||||
VStack(alignment: .leading, spacing: 14) {
|
||||
#if os(iOS)
|
||||
if horizontalSizeClass == .compact {
|
||||
VStack(spacing: 12) {
|
||||
HStack(spacing: 10) {
|
||||
Picker("Appearance", selection: $style.appearance) {
|
||||
ForEach(CodeSnapshotAppearance.allCases) { appearance in
|
||||
Text(appearance.title).tag(appearance)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.menu)
|
||||
.labelsHidden()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Picker("Background", selection: $style.backgroundPreset) {
|
||||
ForEach(CodeSnapshotBackgroundPreset.allCases) { preset in
|
||||
Text(preset.title).tag(preset)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.menu)
|
||||
.labelsHidden()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
|
||||
HStack(spacing: 10) {
|
||||
Picker("Frame", selection: $style.frameStyle) {
|
||||
ForEach(CodeSnapshotFrameStyle.allCases) { frame in
|
||||
Text(frame.title).tag(frame)
|
||||
}
|
||||
}
|
||||
.pickerStyle(.menu)
|
||||
.labelsHidden()
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
|
||||
Toggle("Line Numbers", isOn: $style.showLineNumbers)
|
||||
.toggleStyle(.switch)
|
||||
.lineLimit(1)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HStack(spacing: 16) {
|
||||
Picker("Appearance", selection: $style.appearance) {
|
||||
ForEach(CodeSnapshotAppearance.allCases) { appearance in
|
||||
Text(appearance.title).tag(appearance)
|
||||
}
|
||||
}
|
||||
Picker("Background", selection: $style.backgroundPreset) {
|
||||
ForEach(CodeSnapshotBackgroundPreset.allCases) { preset in
|
||||
Text(preset.title).tag(preset)
|
||||
}
|
||||
}
|
||||
Picker("Frame", selection: $style.frameStyle) {
|
||||
ForEach(CodeSnapshotFrameStyle.allCases) { frame in
|
||||
Text(frame.title).tag(frame)
|
||||
}
|
||||
}
|
||||
Toggle("Line Numbers", isOn: $style.showLineNumbers)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
#else
|
||||
HStack(spacing: 16) {
|
||||
Picker("Appearance", selection: $style.appearance) {
|
||||
ForEach(CodeSnapshotAppearance.allCases) { appearance in
|
||||
|
|
@ -386,6 +478,7 @@ struct CodeSnapshotComposerView: View {
|
|||
}
|
||||
Toggle("Line Numbers", isOn: $style.showLineNumbers)
|
||||
}
|
||||
#endif
|
||||
|
||||
HStack(spacing: 12) {
|
||||
Text("Padding")
|
||||
|
|
|
|||
|
|
@ -930,6 +930,7 @@ extension ContentView {
|
|||
case "log": return "Log"
|
||||
case "ipynb": return "JNB"
|
||||
case "markdown": return "MD"
|
||||
case "tex": return "TeX"
|
||||
case "bash": return "Sh"
|
||||
case "zsh": return "zsh"
|
||||
case "powershell": return "PS"
|
||||
|
|
@ -1019,6 +1020,13 @@ extension ContentView {
|
|||
.disabled(viewModel.selectedTab == nil)
|
||||
.help("Save File (Cmd+S)")
|
||||
|
||||
Button(action: { presentCodeSnapshotComposer() }) {
|
||||
Label("Code Snapshot", systemImage: "camera.viewfinder")
|
||||
.foregroundStyle(macToolbarSymbolColor)
|
||||
}
|
||||
.disabled(!canCreateCodeSnapshot)
|
||||
.help("Create Code Snapshot from Selection")
|
||||
|
||||
Button(action: {
|
||||
showFindReplace = true
|
||||
}) {
|
||||
|
|
|
|||
|
|
@ -1416,6 +1416,9 @@ struct ContentView: View {
|
|||
let selection = (notif.object as? String) ?? ""
|
||||
currentSelectionSnapshotText = selection
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: .editorRequestCodeSnapshotFromSelection)) { _ in
|
||||
presentCodeSnapshotComposer()
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: .pastedText)) { notif in
|
||||
handlePastedTextNotification(notif)
|
||||
}
|
||||
|
|
@ -3233,7 +3236,7 @@ struct ContentView: View {
|
|||
}
|
||||
|
||||
var languageOptions: [String] {
|
||||
["swift", "python", "javascript", "typescript", "php", "java", "kotlin", "go", "ruby", "rust", "cobol", "dotenv", "proto", "graphql", "rst", "nginx", "sql", "html", "expressionengine", "css", "c", "cpp", "csharp", "objective-c", "json", "xml", "yaml", "toml", "csv", "ini", "vim", "log", "ipynb", "markdown", "bash", "zsh", "powershell", "standard", "plain"]
|
||||
["swift", "python", "javascript", "typescript", "php", "java", "kotlin", "go", "ruby", "rust", "cobol", "dotenv", "proto", "graphql", "rst", "nginx", "sql", "html", "expressionengine", "css", "c", "cpp", "csharp", "objective-c", "json", "xml", "yaml", "toml", "csv", "ini", "vim", "log", "ipynb", "markdown", "tex", "bash", "zsh", "powershell", "standard", "plain"]
|
||||
}
|
||||
|
||||
func languageLabel(for lang: String) -> String {
|
||||
|
|
@ -3259,6 +3262,7 @@ struct ContentView: View {
|
|||
case "vim": return "Vim"
|
||||
case "log": return "Log"
|
||||
case "ipynb": return "Jupyter Notebook"
|
||||
case "tex": return "TeX"
|
||||
case "html": return "HTML"
|
||||
case "expressionengine": return "ExpressionEngine"
|
||||
case "css": return "CSS"
|
||||
|
|
@ -3374,6 +3378,8 @@ struct ContentView: View {
|
|||
return "-- TODO: Add queries here\n"
|
||||
case "markdown":
|
||||
return "# Title\n\nWrite here.\n"
|
||||
case "tex":
|
||||
return "\\documentclass{article}\n\\usepackage[utf8]{inputenc}\n\n\\begin{document}\n\\section{Title}\n\nTODO\n\n\\end{document}\n"
|
||||
case "yaml":
|
||||
return "# TODO: Add config here\n"
|
||||
case "json":
|
||||
|
|
@ -3427,7 +3433,7 @@ struct ContentView: View {
|
|||
|
||||
private func detectLanguageWithAppleIntelligence(_ text: String) async -> String {
|
||||
// Supported languages in our picker
|
||||
let supported = ["swift", "python", "javascript", "typescript", "php", "java", "kotlin", "go", "ruby", "rust", "cobol", "dotenv", "proto", "graphql", "rst", "nginx", "sql", "html", "expressionengine", "css", "c", "cpp", "objective-c", "csharp", "json", "xml", "yaml", "toml", "csv", "ini", "vim", "log", "ipynb", "markdown", "bash", "zsh", "powershell", "standard", "plain"]
|
||||
let supported = ["swift", "python", "javascript", "typescript", "php", "java", "kotlin", "go", "ruby", "rust", "cobol", "dotenv", "proto", "graphql", "rst", "nginx", "sql", "html", "expressionengine", "css", "c", "cpp", "objective-c", "csharp", "json", "xml", "yaml", "toml", "csv", "ini", "vim", "log", "ipynb", "markdown", "tex", "bash", "zsh", "powershell", "standard", "plain"]
|
||||
|
||||
#if USE_FOUNDATION_MODELS && canImport(FoundationModels)
|
||||
// Attempt a lightweight model-based detection via AppleIntelligenceAIClient if available
|
||||
|
|
@ -3470,6 +3476,12 @@ struct ContentView: View {
|
|||
if lower.contains(".. code-block::") || lower.contains(".. toctree::") || (lower.contains("::") && lower.contains("\n====")) {
|
||||
return "rst"
|
||||
}
|
||||
if lower.contains("\\documentclass")
|
||||
|| lower.contains("\\usepackage")
|
||||
|| lower.contains("\\begin{document}")
|
||||
|| lower.contains("\\end{document}") {
|
||||
return "tex"
|
||||
}
|
||||
if lower.contains("\n") && lower.range(of: #"(?m)^[A-Z_][A-Z0-9_]*=.*$"#, options: .regularExpression) != nil {
|
||||
return "dotenv"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,6 +329,7 @@ private enum EmmetExpander {
|
|||
extension Notification.Name {
|
||||
static let pastedFileURL = Notification.Name("pastedFileURL")
|
||||
static let editorSelectionDidChange = Notification.Name("editorSelectionDidChange")
|
||||
static let editorRequestCodeSnapshotFromSelection = Notification.Name("editorRequestCodeSnapshotFromSelection")
|
||||
}
|
||||
|
||||
///MARK: - Scope Match Models
|
||||
|
|
@ -3137,6 +3138,35 @@ struct CustomTextEditor: NSViewRepresentable {
|
|||
updateCaretStatusAndHighlight(triggerHighlight: !parent.isLineWrapEnabled)
|
||||
}
|
||||
|
||||
func textView(_ textView: NSTextView, menu: NSMenu, for event: NSEvent, at charIndex: Int) -> NSMenu? {
|
||||
let selectedRange = textView.selectedRange()
|
||||
guard selectedRange.location != NSNotFound,
|
||||
selectedRange.length > 0 else {
|
||||
return menu
|
||||
}
|
||||
let snapshotItem = NSMenuItem(
|
||||
title: "Create Code Snapshot",
|
||||
action: #selector(createCodeSnapshotFromContextMenu(_:)),
|
||||
keyEquivalent: ""
|
||||
)
|
||||
snapshotItem.target = self
|
||||
snapshotItem.image = NSImage(systemSymbolName: "camera.viewfinder", accessibilityDescription: "Create Code Snapshot")
|
||||
menu.addItem(.separator())
|
||||
menu.addItem(snapshotItem)
|
||||
return menu
|
||||
}
|
||||
|
||||
@objc private func createCodeSnapshotFromContextMenu(_ sender: Any?) {
|
||||
guard let tv = textView else { return }
|
||||
let ns = tv.string as NSString
|
||||
let selectedRange = tv.selectedRange()
|
||||
guard selectedRange.location != NSNotFound,
|
||||
selectedRange.length > 0,
|
||||
NSMaxRange(selectedRange) <= ns.length else { return }
|
||||
publishSelectionSnapshot(from: ns, selectedRange: selectedRange)
|
||||
NotificationCenter.default.post(name: .editorRequestCodeSnapshotFromSelection, object: nil)
|
||||
}
|
||||
|
||||
private func publishSelectionSnapshot(from text: NSString, selectedRange: NSRange) {
|
||||
guard selectedRange.location != NSNotFound,
|
||||
selectedRange.length > 0,
|
||||
|
|
@ -4387,6 +4417,25 @@ struct CustomTextEditor: UIViewRepresentable {
|
|||
scheduleHighlightIfNeeded(currentText: textView.text, immediate: immediateHighlight)
|
||||
}
|
||||
|
||||
@available(iOS 16.0, *)
|
||||
func textView(
|
||||
_ textView: UITextView,
|
||||
editMenuForTextIn range: NSRange,
|
||||
suggestedActions: [UIMenuElement]
|
||||
) -> UIMenu? {
|
||||
guard range.length > 0 else { return UIMenu(children: suggestedActions) }
|
||||
let snapshotAction = UIAction(
|
||||
title: "Create Code Snapshot",
|
||||
image: UIImage(systemName: "camera.viewfinder")
|
||||
) { [weak self, weak textView] _ in
|
||||
guard let self, let textView else { return }
|
||||
let nsText = (textView.text ?? "") as NSString
|
||||
self.publishSelectionSnapshot(from: nsText, selectedRange: textView.selectedRange)
|
||||
NotificationCenter.default.post(name: .editorRequestCodeSnapshotFromSelection, object: nil)
|
||||
}
|
||||
return UIMenu(children: suggestedActions + [snapshotAction])
|
||||
}
|
||||
|
||||
private func publishSelectionSnapshot(from text: NSString, selectedRange: NSRange) {
|
||||
guard selectedRange.location != NSNotFound,
|
||||
selectedRange.length > 0,
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ struct NeonSettingsView: View {
|
|||
"swift", "python", "javascript", "typescript", "php", "java", "kotlin", "go", "ruby", "rust",
|
||||
"cobol", "dotenv", "proto", "graphql", "rst", "nginx", "sql", "html", "expressionengine", "css", "c", "cpp",
|
||||
"csharp", "objective-c", "json", "xml", "yaml", "toml", "csv", "ini", "vim", "log", "ipynb",
|
||||
"markdown", "bash", "zsh", "powershell", "standard", "plain"
|
||||
"markdown", "tex", "bash", "zsh", "powershell", "standard", "plain"
|
||||
]
|
||||
|
||||
private var isCompactSettingsLayout: Bool {
|
||||
|
|
@ -2305,6 +2305,7 @@ struct NeonSettingsView: View {
|
|||
case "vim": return "Vim"
|
||||
case "log": return "Log"
|
||||
case "ipynb": return "Jupyter Notebook"
|
||||
case "tex": return "TeX"
|
||||
case "html": return "HTML"
|
||||
case "expressionengine": return "ExpressionEngine"
|
||||
case "css": return "CSS"
|
||||
|
|
@ -2414,6 +2415,8 @@ struct NeonSettingsView: View {
|
|||
return "#!/usr/bin/env \(language)\n\n"
|
||||
case "markdown":
|
||||
return "# Title\n\n"
|
||||
case "tex":
|
||||
return "\\documentclass{article}\n\\usepackage[utf8]{inputenc}\n\n\\begin{document}\n\\section{Title}\n\n\n\\end{document}\n"
|
||||
case "plain":
|
||||
return ""
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -708,6 +708,8 @@ struct ProjectStructureSidebarView: View {
|
|||
return .init(symbol: "curlybraces", color: .green)
|
||||
case "md", "markdown":
|
||||
return .init(symbol: "text.alignleft", color: .teal)
|
||||
case "tex", "latex", "bib", "sty", "cls":
|
||||
return .init(symbol: "text.book.closed", color: .indigo)
|
||||
case "yml", "yaml", "toml", "ini", "env":
|
||||
return .init(symbol: "slider.horizontal.3", color: .mint)
|
||||
case "html", "htm":
|
||||
|
|
|
|||
Loading…
Reference in a new issue