├── .gitignore ├── docs ├── .vitepress │ ├── .gitignore │ ├── theme │ │ ├── index.ts │ │ └── fonts-global.css │ └── config │ │ ├── index.ts │ │ ├── shared.ts │ │ ├── ja.ts │ │ ├── zh.ts │ │ └── en.ts ├── ja │ ├── reference │ │ ├── xml-attributes.md │ │ └── no-implemention.md │ ├── guide │ │ ├── using-color-scheme.md │ │ ├── events-and-components.md │ │ ├── editor-overview.md │ │ ├── using-language.md │ │ └── getting-started.md │ └── index.md ├── zh │ ├── reference │ │ ├── no-implemention.md │ │ ├── xml-attributes.md │ │ └── keybindings.md │ ├── index.md │ └── guide │ │ ├── editor-overview.md │ │ ├── using-color-scheme.md │ │ ├── code-editor-in-compose.md │ │ ├── events-and-components.md │ │ ├── getting-started.md │ │ └── using-language.md ├── guide │ ├── custom-component.md │ ├── custom-language │ │ ├── inlay-hint.md │ │ ├── basics.md │ │ ├── diagnostics.md │ │ ├── code-format.md │ │ ├── syntax-analysis.md │ │ ├── auto-completion.md │ │ └── minor-features.md │ ├── using-lsp.md │ ├── editor-overview.md │ ├── using-color-scheme.md │ ├── code-editor-in-compose.md │ ├── using-composeview-in-popupwindow.md │ ├── events-and-components.md │ ├── getting-started.md │ └── using-language.md ├── reference │ ├── no-implemention.md │ ├── xml-attributes.md │ └── keybindings.md ├── public │ ├── robots.txt │ ├── logo.jpg │ ├── favicon.ico │ └── editor-banner.jpg ├── img │ ├── magnifier-preview.jpg │ ├── auto-completion-preview.jpg │ ├── diagnostic-tooltip-preview.jpg │ └── text-action-window-preview.jpg └── index.md ├── package.json ├── README.md └── .github └── workflows ├── check_pr.yml └── deploy.yml /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea -------------------------------------------------------------------------------- /docs/.vitepress/.gitignore: -------------------------------------------------------------------------------- 1 | cache 2 | dist -------------------------------------------------------------------------------- /docs/ja/reference/xml-attributes.md: -------------------------------------------------------------------------------- 1 | # XML 属性 -------------------------------------------------------------------------------- /docs/zh/reference/no-implemention.md: -------------------------------------------------------------------------------- 1 | 未实现 -------------------------------------------------------------------------------- /docs/zh/reference/xml-attributes.md: -------------------------------------------------------------------------------- 1 | # XML属性 -------------------------------------------------------------------------------- /docs/guide/custom-component.md: -------------------------------------------------------------------------------- 1 | # Custom Component -------------------------------------------------------------------------------- /docs/reference/no-implemention.md: -------------------------------------------------------------------------------- 1 | No implemention -------------------------------------------------------------------------------- /docs/reference/xml-attributes.md: -------------------------------------------------------------------------------- 1 | # XML Attributes -------------------------------------------------------------------------------- /docs/guide/custom-language/inlay-hint.md: -------------------------------------------------------------------------------- 1 | # Inlay Hint -------------------------------------------------------------------------------- /docs/guide/using-lsp.md: -------------------------------------------------------------------------------- 1 | # Language Server Protocol -------------------------------------------------------------------------------- /docs/ja/guide/using-color-scheme.md: -------------------------------------------------------------------------------- 1 | # Color Scheme -------------------------------------------------------------------------------- /docs/ja/reference/no-implemention.md: -------------------------------------------------------------------------------- 1 | No implemention -------------------------------------------------------------------------------- /docs/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | -------------------------------------------------------------------------------- /docs/guide/custom-language/basics.md: -------------------------------------------------------------------------------- 1 | # Custom Language Basics -------------------------------------------------------------------------------- /docs/guide/custom-language/diagnostics.md: -------------------------------------------------------------------------------- 1 | # Language Diagnostics -------------------------------------------------------------------------------- /docs/guide/custom-language/code-format.md: -------------------------------------------------------------------------------- 1 | # Code Format for Language -------------------------------------------------------------------------------- /docs/guide/custom-language/syntax-analysis.md: -------------------------------------------------------------------------------- 1 | # Language Syntax Anslysis -------------------------------------------------------------------------------- /docs/guide/custom-language/auto-completion.md: -------------------------------------------------------------------------------- 1 | # Auto Completion for Language -------------------------------------------------------------------------------- /docs/guide/custom-language/minor-features.md: -------------------------------------------------------------------------------- 1 | # Other Minor Features for Language -------------------------------------------------------------------------------- /docs/public/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-sora/sora-editor-docs/HEAD/docs/public/logo.jpg -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-sora/sora-editor-docs/HEAD/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/public/editor-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-sora/sora-editor-docs/HEAD/docs/public/editor-banner.jpg -------------------------------------------------------------------------------- /docs/img/magnifier-preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-sora/sora-editor-docs/HEAD/docs/img/magnifier-preview.jpg -------------------------------------------------------------------------------- /docs/img/auto-completion-preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-sora/sora-editor-docs/HEAD/docs/img/auto-completion-preview.jpg -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme' 2 | import './fonts-global.css' 3 | 4 | export default DefaultTheme -------------------------------------------------------------------------------- /docs/img/diagnostic-tooltip-preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-sora/sora-editor-docs/HEAD/docs/img/diagnostic-tooltip-preview.jpg -------------------------------------------------------------------------------- /docs/img/text-action-window-preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/project-sora/sora-editor-docs/HEAD/docs/img/text-action-window-preview.jpg -------------------------------------------------------------------------------- /docs/ja/guide/events-and-components.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # Events and Components 5 | ## Event 6 | ### Type of Events 7 | ### Subscribe Events 8 | ## Components 9 | ### Auto Completion 10 | ### Text Action Window 11 | ### Magnifier 12 | ### Diagnostic Tooltip 13 | ### Context Menu -------------------------------------------------------------------------------- /docs/.vitepress/theme/fonts-global.css: -------------------------------------------------------------------------------- 1 | :root{ 2 | --vp-font-family-base: "Chinese Quotes","Inter var", "Inter", ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Helvetica, Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 3 | } -------------------------------------------------------------------------------- /docs/.vitepress/config/index.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | import { shared } from './shared' 3 | import { en } from './en' 4 | import { zh } from './zh' 5 | import { ja } from './ja' 6 | 7 | export default defineConfig({ 8 | ...shared, 9 | locales: { 10 | root: { label: 'English', ...en }, 11 | zh: { label: '简体中文', ...zh }, 12 | ja: { label: '日本語', ...ja } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sora-editor-docs", 3 | "version": "0.24.1", 4 | "type": "module", 5 | "description": "documentation for sora-editor", 6 | "scripts": { 7 | "dev": "vitepress dev docs", 8 | "build": "vitepress build docs", 9 | "preview": "vitepress preview docs" 10 | }, 11 | "devDependencies": { 12 | "markdown-it-mathjax3": "^4.3.2", 13 | "open-cli": "^8.0.0", 14 | "vitepress": "^1.0.0-rc.40" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Welcome 2 | Welcome to [sora-editor](https://github.com/Rosemoe/sora-editor) documentation repository! 3 | The documentation site is available at [GitHub Pages](https://project-sora.github.io/sora-editor-docs/). 4 | 5 | ## Contribution 6 | You are welcome to help make the documentation better. We need your efforts to improve the quality and coverage of the documentation and translate the documentation to other languages so that more people can read it easily. 7 | -------------------------------------------------------------------------------- /docs/.vitepress/config/shared.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress' 2 | 3 | export const shared = defineConfig({ 4 | title: 'Sora Editor', 5 | base: '/sora-editor-docs/', 6 | head: [['link', { rel: 'icon', href: '/sora-editor-docs/favicon.ico' }]], 7 | ignoreDeadLinks: true, 8 | lastUpdated: true, 9 | cleanUrls: true, 10 | 11 | themeConfig: { 12 | logo: '/logo.jpg', 13 | socialLinks: [ 14 | { icon: 'github', link: 'https://github.com/Rosemoe/sora-editor' } 15 | ], 16 | 17 | search: { 18 | provider: 'local' 19 | } 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /.github/workflows/check_pr.yml: -------------------------------------------------------------------------------- 1 | name: Check Pull Request 2 | 3 | on: 4 | pull_request: 5 | types: [opened, reopened] 6 | 7 | jobs: 8 | build: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 0 17 | 18 | - name: Setup Node 19 | uses: actions/setup-node@v4 20 | with: 21 | node-version: 20 22 | cache: npm 23 | 24 | - name: Install dependencies 25 | run: npm ci 26 | 27 | - name: Test build with VitePress 28 | run: | 29 | npm run build -------------------------------------------------------------------------------- /docs/zh/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | title: Sora Editor 5 | titleTemplate: 高性能安卓端代码编辑器 6 | 7 | hero: 8 | name: Sora Editor 9 | text: 高性能安卓端代码编辑器 10 | tagline: 功能强大、性能优化、扩展简易。这是您构建移动端代码编辑程序的不二之选! 11 | actions: 12 | - theme: brand 13 | text: 快速开始 14 | link: /zh/guide/editor-overview 15 | - theme: alt 16 | text: GitHub 17 | link: https://github.com/Rosemoe/sora-editor 18 | features: 19 | - icon: 🛠️ 20 | title: 快速集成 21 | details: 简单易集成,轻轻松松将编辑器集成到您的项目中。 22 | - icon: 🚀 23 | title: 丝滑体验 24 | details: 适时的动画和过渡,让您更加享受您的代码编辑之旅。 25 | - icon: ⚡ 26 | title: 性能高强 27 | details: 通过后台增量分析,使您在眨眼间即可获得代码高亮和精准的提示。 28 | - icon: ✨ 29 | title: 更新活跃 30 | details: 我们仍在不断增强编辑器的功能,让它走在移动端编辑器的前列。 31 | --- 32 | 33 | -------------------------------------------------------------------------------- /docs/ja/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | title: Sora Editor 5 | titleTemplate: 高性能Androidコードエディター 6 | 7 | hero: 8 | name: Sora Editor 9 | text: 高性能Androidコードエディター 10 | tagline: 強力な機能、優秀な性能、簡単な拡張。これは、モバイル コード エディターを構築するために最適な選択です! 11 | actions: 12 | - theme: brand 13 | text: クイックスタート 14 | link: /ja/guide/getting-started 15 | - theme: alt 16 | text: GitHub 17 | link: https://github.com/Rosemoe/sora-editor 18 | features: 19 | - icon: 🛠️ 20 | title: 簡単な拡張 21 | details: エディターをプロジェクトにシンプルで統合や拡張できます。 22 | - icon: 🚀 23 | title: 快適な体験 24 | details: 適切なアニメーションやトランジションにより、コード編集をさらに楽しむことができます。 25 | - icon: ⚡ 26 | title: 優秀な性能 27 | details: バックグラウンドの増分分析を通じて、コードの強調表示と正確なヒントを瞬時に得ることができます。 28 | - icon: ✨ 29 | title: 活躍している更新 30 | details: モバイル エディターの最前線に立つために、私たちはエディターの機能を常に強化しています。 31 | --- 32 | 33 | -------------------------------------------------------------------------------- /docs/zh/guide/editor-overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # 概述 5 | Sora Editor是一个用于编辑代码的Android View库,具有即时语法高亮显示和实时自动补全支持。 6 | 7 | 该编辑器旨在高效、简洁且可扩展,您可以通过将我们的库集成到您的项目中来轻松在应用程序中实现代码编辑。 8 | 9 |
10 | 11 | 现在就想试试?立刻前往[快速开始](./getting-started.md)。 12 | 13 |
14 | 15 | ## 编辑器的亮点 16 | 17 | ### **功能完善** 18 | 19 | Sora Editor实现了现代IDE的大多数功能。我们不仅提供基本功能,还额外提供了最前沿的新功能。 20 | 21 | 目前已实现的功能: 22 | - 语法高亮 23 | - 自动补全(包含对[代码块(Code Snippets)](https://macromates.com/manual/en/snippets)的支持) 24 | - 代码块指示器 25 | - 无限制文本撤回/重做和快速文本搜索/替换 26 | - 自动换行 27 | - 显示不可打印字符 28 | - 诊断标记和工具提示窗口 29 | - 文本放大镜 30 | - 标点符号对匹配和突出显示 31 | - 粘性滚动 32 | - 由[TextMate](https://github.com/eclipse/tm4e)和[TreeSitter](https://github.com/AndroidIDEOfficial/android-tree-sitter/)提供语言支持 33 | 34 | ### **流畅的用户体验** 35 | 36 | Sora Editor使用合适的动画来实现组件的过渡,带来流畅的用户体验(UX)。同时组件还具有PC导航模式和快捷键,以供使用鼠标和实体键盘编辑文本的用户使用组件。 37 | 38 | ### **高性能** 39 | 40 | Sora Editor得益于现代的多核处理器,支持在后台工作线程中以增量方式进行特定语言的代码分析。自动补全待选项按需计算并发送至用户界面进行显示。 41 | 42 | 同时渲染过程也得到了优化。编辑器对可见文本构建测量缓存和[RenderNode](https://developer.android.com/reference/android/graphics/RenderNode),使得编辑器能够快速重新渲染并响应用户的交互。渲染过程使用的大多数对象都会被重用。 43 | 44 | ## 讨论 45 | 46 | 我们创建了用于讨论项目的官方群 47 | - QQ群: [216632648](https://jq.qq.com/?_wv=1027&k=n68uxQws) 48 | - [Telegram群组](https://t.me/rosemoe_code_editor) -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | title: Sora Editor 5 | titleTemplate: High-Performance Android Code Editor 6 | 7 | hero: 8 | name: Sora Editor 9 | text: High-Performance Android Code Editor 10 | tagline: Powerful, optimized and pluggable. Here's what you need for your code viewing and editing apps. 11 | actions: 12 | - theme: brand 13 | text: Get Started 14 | link: /guide/editor-overview 15 | - theme: alt 16 | text: View on GitHub 17 | link: https://github.com/Rosemoe/sora-editor 18 | 19 | features: 20 | - icon: 🛠️ 21 | title: Fast Integration 22 | details: Effortlessly integrate the editor into your project with documentation and detailed javadoc. 23 | - icon: 🚀 24 | title: Smooth User Experience 25 | details: Enjoy coding comfort with suitable animations and trasitions. 26 | - icon: ⚡ 27 | title: High Performance 28 | details: Run analysis in background workers, incrementally. Get syntax-highlight and code completions in a glance. 29 | - icon: ✨ 30 | title: Active Development 31 | details: We are continuously enhancing the functionality of the editor to keep it at the forefront of mobile editors. 32 | --- 33 | 34 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy document to Pages 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | 7 | workflow_dispatch: 8 | 9 | permissions: 10 | contents: read 11 | pages: write 12 | id-token: write 13 | 14 | concurrency: 15 | group: pages 16 | cancel-in-progress: false 17 | 18 | jobs: 19 | build: 20 | 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v4 26 | with: 27 | fetch-depth: 0 28 | 29 | - name: Setup Node 30 | uses: actions/setup-node@v4 31 | with: 32 | node-version: 20 33 | cache: npm 34 | 35 | - name: Setup Pages 36 | uses: actions/configure-pages@v4 37 | 38 | - name: Install dependencies 39 | run: npm ci 40 | 41 | - name: Build with VitePress 42 | run: | 43 | npm run build 44 | touch docs/.vitepress/dist/.nojekyll 45 | 46 | - name: Upload artifact 47 | uses: actions/upload-pages-artifact@v3 48 | with: 49 | path: docs/.vitepress/dist 50 | 51 | deploy: 52 | environment: 53 | name: github-pages 54 | url: ${{ steps.deployment.outputs.page_url }} 55 | needs: build 56 | runs-on: ubuntu-latest 57 | name: Deploy 58 | steps: 59 | - name: Deploy to GitHub Pages 60 | id: deployment 61 | uses: actions/deploy-pages@v4 -------------------------------------------------------------------------------- /docs/ja/guide/editor-overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # 概要 5 | Sora Editor はコード編集用の Android View ライブラリで、インスタント構文ハイライトとリアルタイムのオートコンプリート サポートを備えています。 6 | 7 | このエディターは効果的でスムーズでプラグイン可能であるように設計されており、ライブラリをプロジェクトに統合することでコード編集アプリを簡単に開始できます。 8 | 9 | 10 |
11 | 12 | 試してみたいですか? [クイックスタート](./getting-started.md)に参照してください。 13 | 14 |
15 | 16 | ## Sora Editor のハイライツ 17 | ### **強力な機能** 18 | Sora Editor は、最新の IDE のほとんどの機能を実装しています。 基本的なものだけでなく、最先端の機能も提供します。 19 | 20 | これまでに実装された機能: 21 | - インクリメンタル構文のハイライト 22 | - オートコンプリート ([コード スニペット](https://macromates.com/manual/en/snippets) 付き) 23 | - コードブロックインジケーター 24 | - 無制限のテキスト取り消しスタックと高速検索置換 25 | - ワードラップ表示モード 26 | - 印刷できない文字を表示する 27 | - 診断マーカーとツールチップ ウィンドウ 28 | - テキスト拡大鏡 29 | - 句読点ペアのマッチングと強調表示 30 | - スティッキースクロール 31 | - [TextMate](https://github.com/eclipse/tm4e) および [TreeSitter](https://github.com/AndroidIDEOfficial/android-tree-sitter/) による言語サポート 32 | 33 | ### **快適な体験** 34 | Sora Editor は適切なアニメーションを使用してコンポーネントの遷移を補間し、スムーズなユーザー エクスペリエンス (UX) を実現します。 このウィジェットには、マウスとハードウェア キーボードを使用してテキストを編集するユーザー向けの PC ナビゲーション モードとキー バインドもあります。 35 | ### **優秀な性能** 36 | Sora Editor は、バックグラウンド ワーカーで言語固有のコード分析を段階的にサポートすることで、最新のマルチコア プロセッサの恩恵を受けています。 オートコンプリート項目はオンデマンドで計算され、UI に公開されます。 37 | 38 | レンダリングプロセスも最適化されています。 エディターは、表示テキストの測定キャッシュと [RenderNode](https://developer.android.com/reference/android/graphics/RenderNode) を構築します。これにより、エディターは高速に再レンダリングし、ユーザー インタラクションに迅速に応答できます。レンダリング プロセスで使用されるほとんどのオブジェクトは再利用されます。 39 | ## ディスカッション 40 | プロジェクトのディスカッションのための公式グループを作成しました。 41 | - QQ グループ: [216632648](https://jq.qq.com/?_wv=1027&k=n68uxQws) 42 | - [Telegram グループ](https://t.me/rosemoe_code_editor) -------------------------------------------------------------------------------- /docs/zh/guide/using-color-scheme.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | 5 | # 配色方案 6 | 7 | 编辑器的配色方案由(`EditorColorScheme`)管理. 8 | 9 | 颜色类型由不同的整数 ID 表示。`EditorColorScheme`内部维护颜色类型ID到实际颜色的映射。内置颜色类型应定义为类中静态的整数常量。 10 | 11 | 与`Language`不同的是,同一个`EditorColorScheme`实例可以为多个编辑器服务,配色方案会通知它所服务的所有编辑器,以更新其渲染结果。您可以使用共享的配色方案实例管理编辑器文本的效果。当调用`CodeEditor#release`的时候,编辑器会和它的配色方案解绑。 12 | 13 | 编辑器对象在这个类中是`弱引用`的,因此编辑器可以被安全的释放。 14 | 15 | ## 更新配色方案 16 | 17 | 通过`CodeEditor#getColorScheme`获取编辑器的配色方案。 18 | 19 | 使用`EditorColorScheme#setColor(int, int)`将新颜色应用于编辑器。 20 | 21 | 示例: 22 | 23 | ::: code-group 24 | ```Kotlin 25 | val scheme = editor.colorScheme 26 | scheme.setColor(EditorColorScheme.KEYWORD, Color.RED) 27 | ``` 28 | ```Java 29 | var scheme = editor.getColorScheme(); 30 | scheme.setColor(EditorColorScheme.KEYWORD, Color.RED); 31 | ``` 32 | ::: 33 | 34 | 请注意,多个编辑器可以共享相同的配色方案。更改一个编辑器的配色方案也可能导致其他编辑器的颜色更改。 35 | 36 | ## 扩展配色方案 37 | 38 | 有时我们需要扩展类以更好地定义您自己的配色方案。 39 | 40 | ### 覆盖默认颜色 41 | 42 | 子类应重写`applyDefault()`以应用其默认颜色,尽管其他方法没有被final修饰。 43 | 44 | 重写此方法后,您必须调用超类的`applyDefault()`,然后调用一系列setColor(int, int)应用您自己的配色。有时我们会在编辑器库中添加新的颜色类型。如果不调用超类的方法,可能会缺少一些重要的颜色。 45 | 46 | ### 添加新的颜色类型 47 | 48 | 您可以将不在预定义池中的颜色ID用于自定义Language。我们建议您为自定义颜色ID添加一个基本的偏移量。例如,第一个自定义颜色类型 ID 是`256`。这可以为编辑器后面的内置类型预留足够的空间并且有效的避免后续的ID冲突。 49 | 50 | 最后一个预定义的颜色类型ID是`EditorColorScheme.END_COLOR_ID`。 51 | 52 | ## 默认配色方案 53 | 54 | 默认情况下,新创建的编辑器使用全局默认配色方案。默认配色方案由这些编辑器共享,可从`EditorColorScheme#getDefault`获取。 55 | 56 | 您可以通过`EditorColorScheme#setDefault`更新全局默认配色方案。 57 | 58 | * 更新全局默认配色方案。新创建的编辑器将使用新的默认配色方案。 59 | 60 | ::: code-group 61 | ```Kotlin 62 | EditorColorScheme.setDefault(MyColorScheme()) 63 | ``` 64 | ```Java 65 | EditorColorScheme.setDefault(new MyColorScheme()); 66 | ``` 67 | ::: 68 | 69 | * 更新全局默认配色方案,并同时应用于使用了旧默认配色方案的编辑器 70 | 71 | ::: code-group 72 | ```Kotlin 73 | EditorColorScheme.setDefault(MyColorScheme(), true) 74 | ``` 75 | ```Java 76 | EditorColorScheme.setDefault(new MyColorScheme(), true); 77 | ``` 78 | ::: -------------------------------------------------------------------------------- /docs/guide/editor-overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # Overview 5 | Sora Editor is an Android View library for editing code, with instant syntax-highlight and real-time auto-completion support. 6 | 7 | The editor is desgined to be effective, smooth and pluggable, and you can easily start a code editting app by integrating our library into your project. 8 | 9 | 10 |
11 | 12 | Just want to try it out? Go to [Getting Started](./getting-started.md). 13 | 14 |
15 | 16 | ## Highlights of Our Editor 17 | ### **Full-Featured** 18 | Sora Editor has implemented most features of modern IDEs. We provide not only fundamental stuff, but also forefront functionaliy. 19 | 20 | Features implemented up to now: 21 | - Incremental Syntax-highlight 22 | - Auto-Completion (with [code snippets](https://macromates.com/manual/en/snippets)) 23 | - Code Block Indicators 24 | - Unlimited Text Undo Stack and Fast Search-Replace 25 | - Word Wrap Display Mode 26 | - Display Non-Printable Characters 27 | - Diagnostic Markers and Tooltip Window 28 | - Text Magnifier 29 | - Punctuation Pair Matching and Highlighting 30 | - Sticky Scroll 31 | - Language Support backed by [TextMate](https://github.com/eclipse/tm4e) and [TreeSitter](https://github.com/AndroidIDEOfficial/android-tree-sitter/) 32 | 33 | ### **Smooth User Experience** 34 | Sora Editor uses suitable animations to interpolate the transitions of components, bringing a smooth User Experience (UX). The widget also has a PC navigation mode and key bindings for users who use mouse and hardware keyboard to edit texts. 35 | ### **High-Performance** 36 | Sora Editor benefits from modern multi-core processors by supporting language-specific code analysis incrementally in background workers. Auto-completion items are computed and published to UI on demand. 37 | 38 | The rendering process is also optimized. The editor builds measuring caches and [RenderNode](https://developer.android.com/reference/android/graphics/RenderNode)s for visible text, which enables the editor to re-render fast and respond to user interaction quickly. Most objects used by the rendering process are reused. 39 | ## Discussion 40 | We have created official group for project discussions. 41 | - QQ Group: [216632648](https://jq.qq.com/?_wv=1027&k=n68uxQws) 42 | - [Telegram Group](https://t.me/rosemoe_code_editor) 43 | -------------------------------------------------------------------------------- /docs/.vitepress/config/ja.ts: -------------------------------------------------------------------------------- 1 | import config from '../../../package.json' 2 | import {type DefaultTheme, defineConfig} from 'vitepress' 3 | 4 | export const ja = defineConfig({ 5 | lang: 'ja', 6 | description: 'sora-editor は効率的な Android コードエディターです', 7 | 8 | themeConfig: { 9 | nav: nav(), 10 | 11 | sidebar: { 12 | '/ja/reference/': { base: '/ja/reference/', items: sidebarReference() }, 13 | '/ja/guide/': { base: '/ja/guide/', items: guideReference() } 14 | }, 15 | 16 | editLink: { 17 | pattern: 'https://github.com/project-sora/sora-editor-docs/blob/main/docs/:path', 18 | text: 'GitHub でこのページを編集する' 19 | }, 20 | 21 | footer: { 22 | message: 'LGPL-2.1 ライセンスに基づいてリリース', 23 | copyright: `著作権 © 2020-${new Date().getFullYear()} Rosemoe` 24 | }, 25 | 26 | docFooter: { 27 | prev: '前のページ', 28 | next: '次のページ' 29 | }, 30 | 31 | outline: { 32 | label: 'ナビゲーション' 33 | }, 34 | 35 | lastUpdated: { 36 | text: '最終更新日', 37 | formatOptions: { 38 | dateStyle: 'short', 39 | timeStyle: 'medium' 40 | } 41 | }, 42 | 43 | langMenuLabel: '言語', 44 | returnToTopLabel: 'トップに戻る', 45 | sidebarMenuLabel: 'メニュー', 46 | darkModeSwitchLabel: 'テーマ', 47 | lightModeSwitchTitle: 'ライトモードに切り替える', 48 | darkModeSwitchTitle: 'ダークモードに切り替える' 49 | } 50 | }) 51 | 52 | function nav(): DefaultTheme.NavItem[] { 53 | return [ 54 | { 55 | text: 'ガイド', 56 | link: '/ja/guide/editor-overview', 57 | activeMatch: '/ja/guide/' 58 | }, 59 | { 60 | text: '参考', 61 | link: '/ja/reference/no-implemention', 62 | activeMatch: '/ja/reference/' 63 | }, 64 | { 65 | text: config.version, 66 | items: [ 67 | { 68 | text: 'リリース', 69 | link: 'https://github.com/Rosemoe/sora-editor/releases' 70 | }, 71 | { 72 | text: '贡献者', 73 | link: 'https://github.com/Rosemoe/sora-editor/graphs/contributors' 74 | } 75 | ] 76 | } 77 | ] 78 | } 79 | 80 | function guideReference(): DefaultTheme.SidebarItem[] { 81 | return [ 82 | { 83 | text: '概要と開始方法', 84 | collapsed: false, 85 | items: [ 86 | { 87 | text: '概要', 88 | link: 'editor-overview' 89 | }, 90 | { 91 | text: 'クイックスタート', 92 | link: 'getting-started' 93 | }, 94 | { text: '言語', link: 'using-language'}, 95 | { text: 'カラースキーム', link: 'using-color-scheme' }, 96 | { text: 'イベントとコンポーネント', link: 'events-and-components' } 97 | ] 98 | } 99 | ] 100 | } 101 | 102 | function sidebarReference(): DefaultTheme.SidebarItem[] { 103 | return [ 104 | { 105 | items: [ 106 | { 107 | text: 'XML 属性', 108 | link: 'xml-attributes' 109 | } 110 | ] 111 | } 112 | ] 113 | } -------------------------------------------------------------------------------- /docs/.vitepress/config/zh.ts: -------------------------------------------------------------------------------- 1 | import config from '../../../package.json' 2 | import {type DefaultTheme, defineConfig} from 'vitepress' 3 | 4 | export const zh = defineConfig({ 5 | lang: 'zh-Hans', 6 | description: 'sora-editor是一款高效的安卓代码编辑器', 7 | 8 | themeConfig: { 9 | nav: nav(), 10 | 11 | sidebar: { 12 | '/zh/reference/': { base: '/zh/reference/', items: sidebarReference() }, 13 | '/zh/guide/': { base: '/zh/guide/', items: guideReference() } 14 | }, 15 | 16 | editLink: { 17 | pattern: 'https://github.com/project-sora/sora-editor-docs/blob/main/docs/:path', 18 | text: '在 GitHub 上编辑此页面' 19 | }, 20 | 21 | footer: { 22 | message: '基于 LGPL-2.1 许可发布', 23 | copyright: `版权所有 © 2020-${new Date().getFullYear()} Rosemoe` 24 | }, 25 | 26 | docFooter: { 27 | prev: '上一页', 28 | next: '下一页' 29 | }, 30 | 31 | outline: { 32 | label: '页面导航' 33 | }, 34 | 35 | lastUpdated: { 36 | text: '最后更新于', 37 | formatOptions: { 38 | dateStyle: 'short', 39 | timeStyle: 'medium' 40 | } 41 | }, 42 | 43 | langMenuLabel: '多语言', 44 | returnToTopLabel: '回到顶部', 45 | sidebarMenuLabel: '菜单', 46 | darkModeSwitchLabel: '主题', 47 | lightModeSwitchTitle: '切换到浅色模式', 48 | darkModeSwitchTitle: '切换到深色模式' 49 | } 50 | }) 51 | 52 | function nav(): DefaultTheme.NavItem[] { 53 | return [ 54 | { 55 | text: '指南', 56 | link: '/zh/guide/editor-overview', 57 | activeMatch: '/zh/guide/' 58 | }, 59 | { 60 | text: '参考', 61 | link: '/zh/reference/xml-attributes', 62 | activeMatch: '/zh/reference/' 63 | }, 64 | { 65 | text: config.version, 66 | items: [ 67 | { 68 | text: '更新日志', 69 | link: 'https://github.com/Rosemoe/sora-editor/releases' 70 | }, 71 | { 72 | text: '参与贡献', 73 | link: 'https://github.com/Rosemoe/sora-editor/graphs/contributors' 74 | } 75 | ] 76 | } 77 | ] 78 | } 79 | 80 | function guideReference(): DefaultTheme.SidebarItem[] { 81 | return [ 82 | { 83 | text: '简介与入门', 84 | collapsed: false, 85 | items: [ 86 | { text: '概述', link: 'editor-overview' }, 87 | { text: '快速开始', link: 'getting-started' }, 88 | { text: '语言支持', link: 'using-language' }, 89 | { text: '配色方案', link: 'using-color-scheme' }, 90 | { text: '事件和组件', link: 'events-and-components' } 91 | ] 92 | }, 93 | { 94 | text: 'Jetpack Compose', 95 | collapsed: false, 96 | items: [ 97 | { text: '在Compose中使用代码编辑器', link: 'code-editor-in-compose'} 98 | ] 99 | }, 100 | ] 101 | } 102 | 103 | function sidebarReference(): DefaultTheme.SidebarItem[] { 104 | return [ 105 | { 106 | text: '参考', 107 | items: [ 108 | { text: 'XML属性', link: 'xml-attributes' }, 109 | { text: '快捷键', link: 'keybindings' } 110 | ] 111 | } 112 | ] 113 | } -------------------------------------------------------------------------------- /docs/guide/using-color-scheme.md: -------------------------------------------------------------------------------- 1 | # Color Scheme 2 | Color scheme (`EditorColorScheme`) manages the colors of editor. 3 | 4 | Color types are represented by distinct integer IDs. `EditorColorScheme` internally maintains a map of color type ID to actual color. Built-in color types are defined as static integer constants in the class. 5 | 6 | Unlike `Language`, single `EditorColorScheme` instance can be applied to multiple editors. Color scheme will notify all the editor it serves, to update their appearance. You can manage appearance of your editors easily by using shared color scheme instance. Editor will detached from its color scheme when `CodeEditor#release` is invoked. 7 | 8 | The class holds editor by `WeakReference`, so editors can be safely recycled. 9 | 10 | ## Update Color Scheme 11 | Get the color scheme of an editor by `CodeEditor#getColorScheme`. 12 | 13 | Use `EditorColorScheme#setColor(int, int)` to apply new colors to the editor. 14 | 15 | Example: 16 | ::: code-group 17 | ```Kotlin 18 | val scheme = editor.colorScheme 19 | scheme.setColor(EditorColorScheme.KEYWORD, Color.RED) 20 | ``` 21 | ```Java 22 | var scheme = editor.getColorScheme(); 23 | scheme.setColor(EditorColorScheme.KEYWORD, Color.RED); 24 | ``` 25 | ::: 26 | Be careful that multiple editors can share the same color scheme. Changing color scheme of one editor may lead to color changes in other editors, too. 27 | 28 | ## Extend the Color Scheme 29 | Sometimes we need to extend the class to better define your own color scheme. 30 | ### Override Default Colors 31 | Subclasses are expected to override `applyDefault()` to apply its default colors, though other methods are not final. 32 | 33 | After overriding this method, you will have to call super class's `applyDefault()` and then a series of setColor(int, int) calls to apply your colors. Sometimes we add new color types in the editor library. If super method is not called, some vital colors can be missing. 34 | ### Add New Color Types 35 | You can use color IDs that are not in pre-defined ID pool for custom languages. We recommend adding a base offset for your custom color IDs. For example, first custom color type ID is `256`. This leaves enough space for editor's future built-in colors. 36 | 37 | The last pre-defined color type ID is `EditorColorScheme.END_COLOR_ID`. 38 | ## Default Color Scheme 39 | By default, newly-created editor uses the global default color scheme. The default color scheme is shared by those editors, and can be obtained from `EditorColorScheme#getDefault`. 40 | 41 | You can update global default color scheme by `EditorColorScheme#setDefault`. 42 | * Update global default color scheme. Newly-created editor will use the new default color scheme. 43 | ::: code-group 44 | ```Kotlin 45 | EditorColorScheme.setDefault(MyColorScheme()) 46 | ``` 47 | ```Java 48 | EditorColorScheme.setDefault(new MyColorScheme()); 49 | ``` 50 | ::: 51 | * Update global default color scheme, and also apply to editors that are using the old default color scheme 52 | ::: code-group 53 | ```Kotlin 54 | EditorColorScheme.setDefault(MyColorScheme(), true) 55 | ``` 56 | ```Java 57 | EditorColorScheme.setDefault(new MyColorScheme(), true); 58 | ``` 59 | ::: -------------------------------------------------------------------------------- /docs/zh/guide/code-editor-in-compose.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | 5 | # CodeEditor in Compose 6 | 7 | Jetpack Compose是用于Android开发的新框架。如果您尝试使用Sora Editor,同时使用使用Jetpack Compose构建的应用程序。本文档可能会对您有所帮助。 8 | 9 | > 我的英语可能不好,如果有的话请纠正它们。谢谢。 10 | 11 | ## 创建状态持有者 12 | 13 | 首先,我们将定义一个`CodeEditorState`,封装并持有`CodeEditor`的状态. 14 | 15 | ```kotlin 16 | data class CodeEditorState( 17 | val editor: CodeEditor? = null, 18 | val initialContent: Content = Content() 19 | ) { 20 | var content by mutableStateOf(initialContent) 21 | } 22 | ``` 23 | 24 | 您可以根据需要添加许多状态。 25 | 26 | ::: tip 注意 27 | 如果您不想使用`ViewModel`而是希望使用`remember*()`可组合函数,您可以进行以下操作: 28 | 29 | ```kotlin 30 | @Composable 31 | fun rememberCodeEditorState( 32 | initialContent: Content = Content() 33 | ) = remember { 34 | CodeEditorState( 35 | initialContent = initialContent 36 | ) 37 | } 38 | ``` 39 | ::: 40 | 41 | ## 创建`CodeEditor`可组合项 42 | 43 | 现在,我们将创建`CodeEditor`可组合项,它通过`AndroidView`间接地实现可组合化。在这个可组合项中,它将接受一个与`CodeEditorState`类型的参数`state`. 44 | 45 | ```kotlin 46 | @Composable 47 | fun CodeEditor( 48 | modifier: Modifier = Modifier, 49 | state: CodeEditorState 50 | ) { 51 | // ... 52 | } 53 | ``` 54 | 55 | ### 设置`CodeEditor`工厂 56 | 57 | 我们需要一个`Context`以实例化一个`CodeEditor`。 58 | 59 | ```kotlin 60 | private fun setCodeEditorFactory( 61 | context: Context, 62 | state: CodeEditorState 63 | ): CodeEditor { 64 | val editor = CodeEditor(context) 65 | editor.apply { 66 | setText(state.content) 67 | // ... 68 | } 69 | state.editor = editor 70 | return editor 71 | } 72 | ``` 73 | 74 | 一旦我们完成了工厂的创建,我们现在就可以用`remember`可组合函数进行管理. 75 | 76 | ```kotlin 77 | @Composable 78 | fun CodeEditor( 79 | modifier: Modifier = Modifier, 80 | state: CodeEditorState 81 | ) { 82 | val context = LocalContext.current 83 | val editor = remember { 84 | setCodeEditorFactory( 85 | context = context, 86 | state = state 87 | ) 88 | } 89 | AndroidView( 90 | factory = { editor }, 91 | modifier = modifier, 92 | onRelease = { 93 | it.release() 94 | } 95 | ) 96 | // ... 97 | } 98 | ``` 99 | 100 | ### 为`CodeEditor`的状态设置`LaunchedEffect` 101 | 102 | 当`CodeEditor`的状态发生变化时执行某些代码,我们需要使用`LaunchedEffect` 103 | 104 | ```kotlin 105 | LaunchedEffect(key1 = state.content) { 106 | state.editor?.setText(state.content) 107 | } 108 | ``` 109 | 110 | ## 使用`CodeEditor`可组合项 111 | 112 | 在我们完成`CodeEditor`可组合项后,我们就可以在应用程序中使用它。首先,**强烈建议**在`ViewModel`中定义`CodeEditorState`。 113 | 114 | 例如,在`MainScreen`中,我们将创建一个`MainViewModel`,在这个viewmodel中,我们定义了一个`CodeEditorState`。 115 | 116 | ```kotlin 117 | class MainViewModel : ViewModel() { 118 | val editorState by mutableStateOf( 119 | CodeEditorState() 120 | ) 121 | } 122 | ``` 123 | 124 | 接着在`MainScreen`可组合项中,使用`Modifier`对您的`CodeEditor`进行必要的调整。 125 | 126 | ```kotlin 127 | @Composable 128 | fun MainScreen( 129 | viewModel: MainViewModel = viewModel() 130 | ) { 131 | Column { 132 | CodeEditor( 133 | modifier = Modifier 134 | .fillMaxSize(), 135 | state = viewModel.editorState 136 | ) 137 | } 138 | } 139 | ``` 140 | 141 | ::: warning 警告 142 | 如果`CodeEditor`的底部有可组合项,请使用`Modifier.weight(1f)`而不是`Modifier.fillMaxSize()`。否则`CodeEditor`将会占满整个容器。 143 | ::: 144 | 145 | ## 结语 146 | 147 | 一般情况下,`CodeEditor`是我们唯一需要使用`AndroidView`的小部件。至于其他类似于`SymbolInputView`的组件,目前建议完全使用Compose进行实现。 148 | 149 | --- 150 | 151 | 以上便是全部。我并不知道在JetPack Compose中使用Sora编辑器的`CodeEditor`是否是一个正确的选择,但我希望您能通过本指南获得灵感。感谢您的阅读。 -------------------------------------------------------------------------------- /docs/zh/reference/keybindings.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | 5 | # 快捷键 6 | 当您使用物理键盘工作时,您可以使用快捷键来执行各种文本操作。 7 | 8 | 默认情况下,编辑器默认支持部分快捷键。目前支持的键绑定大多类似于Android Studio/IntelliJ IDEA。 9 | 10 | ## 内置快捷键 11 | 12 | 编辑器目前支持以下快捷键: 13 | 14 | | 快捷键 | 描述 | 15 | | ---------------------- | -------------------------------------------------------------------------------------- | 16 | | `Ctrl + A` | 全选。 | 17 | | `Ctrl + X` | 如果没有选定内容,则剪切当前行。否则,执行通常的剪切操作。 | 18 | | `Ctrl + C` | 如果没有选定内容,则选择并复制当前行。否则,执行通常的复制操作。 | 19 | | `Ctrl + V` | 常规粘贴操作。 | 20 | | `Ctrl + Z` | 撤销上一步操作。 | 21 | | `Ctrl + R` | 重做上一步操作。 | 22 | | `Ctrl + D` | 如果有选定内容,则复制选定内容,否则复制当前行。 | 23 | | `Ctrl + W` | 选择光标左侧的单词。 | 24 | | `Ctrl + Left` | 移动到单词开头。如果光标已在当前单词的开头,则将光标移动到前一个单词的开头,跳过空格。 | 25 | | `Ctrl + Right` | 移动到单词结尾。如果光标已在当前单词的结尾,则将光标移动到下一个单词的结尾,跳过空格。 | 26 | | `Ctrl + Up` | 向上滚动一行。 | 27 | | `Ctrl + Down` | 向下滚动一行。 | 28 | | `Ctrl + Home` | 将光标移动到内容开头。 | 29 | | `Ctrl + End` | 将光标移动到内容结尾。 | 30 | | `Ctrl + PgUp` | 将光标移动到页面顶部。 | 31 | | `Ctrl + PgDn` | 将光标移动到页面底部。 | 32 | | `Ctrl + Enter` | 拆分当前行。如果有选定内容,则先删除选定内容,然后拆分当前行。 | 33 | | `Ctrl + Shift + Left` | 与`Ctrl+Left`相同,但会开始或者扩大文本选择范围。 | 34 | | `Ctrl + Shift + Right` | 与`Ctrl+Right`相同,但会开始或者扩大文本选择范围。 | 35 | | `Ctrl + Shift + Up` | 将当前行(或所有选定行)上移一行。 | 36 | | `Ctrl + Shift + Down` | 将当前行(或所有选定行)下移一行。 | 37 | | `Ctrl + Shift + Home` | 与`Ctrl+Home`相同,但开始或者扩大文本选择范围。 | 38 | | `Ctrl + Shift + End` | 与`Ctrl+End`相同,但开始或者扩大文本选择范围。 | 39 | | `Ctrl + Shift + PgUp` | 将光标移动到页面顶部并选择旧位置到新位置的文本。 | 40 | | `Ctrl + Shift + PgDn` | 将光标移动到页面底部并选择旧位置到新位置的文本。 | 41 | | `Ctrl + Alt + Enter` | 在当前行之前插入新行。 | 42 | | `Ctrl + Shift + J` | 连接当前行和下一行。 | 43 | | `Shift + Enter` | 开始一行新行。 | 44 | | `选定文本 + TAB` | 如果已经选择文本,则按`TAB`键将会缩进所有选定行。 | 45 | | `Shift + TAB` | 减少当前行的缩进。如果已经选择文本,则减少所选行的缩进。 | 46 | 47 | ## 自定义快捷键 48 | 49 | 你可以订阅[`KeyBindingEvent`](https://github.com/Rosemoe/sora-editor/blob/main/editor/src/main/java/io/github/rosemoe/sora/event/KeyBindingEvent.java)并且添加自己的快捷键。你甚至可以覆盖默认的按键绑定并执行自定义操作。 -------------------------------------------------------------------------------- /docs/.vitepress/config/en.ts: -------------------------------------------------------------------------------- 1 | import config from '../../../package.json' 2 | import {type DefaultTheme, defineConfig} from 'vitepress' 3 | 4 | 5 | export const en = defineConfig({ 6 | lang: 'en-US', 7 | description: 'sora-editor is a cool and optimized code editor on Android platform', 8 | 9 | themeConfig: { 10 | nav: nav(), 11 | 12 | sidebar: { 13 | '/reference/': { base: '/reference/', items: sidebarReference() }, 14 | '/guide/': { base: '/guide/', items: guideReference() } 15 | }, 16 | 17 | editLink: { 18 | pattern: 'https://github.com/project-sora/sora-editor-docs/blob/main/docs/:path', 19 | text: 'Edit this page on GitHub' 20 | }, 21 | 22 | footer: { 23 | message: 'Released under the LGPL-2.1 License.', 24 | copyright: `Copyright © 2020-${new Date().getFullYear()} Rosemoe` 25 | } 26 | } 27 | }) 28 | 29 | function nav(): DefaultTheme.NavItem[] { 30 | return [ 31 | { 32 | text: 'Guide', 33 | link: '/guide/editor-overview', 34 | activeMatch: '/guide/' 35 | }, 36 | { 37 | text: 'Reference', 38 | link: '/reference/xml-attributes', 39 | activeMatch: '/reference/' 40 | }, 41 | { 42 | text: config.version, 43 | items: [ 44 | { 45 | text: 'Changelog', 46 | link: 'https://github.com/Rosemoe/sora-editor/releases' 47 | }, 48 | { 49 | text: 'Contributing', 50 | link: 'https://github.com/Rosemoe/sora-editor/graphs/contributors' 51 | } 52 | ] 53 | } 54 | ] 55 | } 56 | 57 | function guideReference(): DefaultTheme.SidebarItem[] { 58 | return [ 59 | { 60 | text: 'Introduction', 61 | collapsed: false, 62 | items: [ 63 | { text: 'Overview', link: 'editor-overview' }, 64 | { text: 'Getting Started', link: 'getting-started' }, 65 | { text: 'Language', link: 'using-language'}, 66 | { text: 'Color Scheme', link: 'using-color-scheme' }, 67 | { text: 'Events and Components', link: 'events-and-components' } 68 | ] 69 | }, 70 | { 71 | text: 'Advanced', 72 | collapsed: false, 73 | items: [ 74 | { text: 'Language Server Protocol', link: 'using-lsp' }, 75 | { text: 'Custom Component', link: 'custom-component' }, 76 | { 77 | text: 'Custom Language', 78 | collapsed: true, 79 | items: [ 80 | { text: 'Language Basics', link: 'custom-language/basics' }, 81 | { text: 'Syntax Analysis', link: 'custom-language/syntax-analysis' }, 82 | { text: 'Auto Completion', link: 'custom-language/auto-completion' }, 83 | { text: 'Diagnostics', link: 'custom-language/diagnostics' }, 84 | { text: 'Code Format', link: 'custom-language/code-format' }, 85 | // { text: 'Inlay Hint', link: 'custom-language/inlay-hint' }, 86 | { text: 'Minor Features', link: 'custom-language/minor-features' } 87 | ] 88 | } 89 | ] 90 | }, 91 | { 92 | text: 'Jetpack Compose', 93 | collapsed: false, 94 | items: [ 95 | { text: 'CodeEditor in Compose', link: 'code-editor-in-compose'}, 96 | { text: 'Using ComposeView in PopupWindow', link: 'using-composeview-in-popupwindow'}, 97 | ] 98 | }, 99 | { 100 | text: 'API Reference', 101 | link: '../reference/xml-attributes' 102 | } 103 | ] 104 | } 105 | 106 | function sidebarReference(): DefaultTheme.SidebarItem[] { 107 | return [ 108 | { 109 | text: 'Reference', 110 | items: [ 111 | { text: 'XML Attributes', link: 'xml-attributes' }, 112 | { text: 'Keybindings', link: 'keybindings' } 113 | ] 114 | } 115 | ] 116 | } -------------------------------------------------------------------------------- /docs/guide/code-editor-in-compose.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | 5 | # CodeEditor in Compose 6 | 7 | Jetpack Compose is a new framework for Android development. If you are attempting to use Sora Editor, while working on apps built with Jetpack Compose. This documentation might help you. 8 | 9 | > The guide and code, and my english perhaps are not good, please correct them if there's any. Thank you. 10 | 11 | ## Create a State holder 12 | 13 | First, we will define a `CodeEditorState` which wraps the states of the `CodeEditor`. 14 | 15 | ```kotlin 16 | data class CodeEditorState( 17 | val editor: CodeEditor? = null, 18 | val initialContent: Content = Content() 19 | ) { 20 | var content by mutableStateOf(initialContent) 21 | } 22 | ``` 23 | 24 | You can add many states as you want. 25 | 26 | ::: tip NOTE 27 | If you are not using `ViewModel` and want to make a `remember*()` composable function, you can do following: 28 | ```kotlin 29 | @Composable 30 | fun rememberCodeEditorState( 31 | initialContent: Content = Content() 32 | ) = remember { 33 | CodeEditorState( 34 | initialContent = initialContent 35 | ) 36 | } 37 | ``` 38 | ::: 39 | 40 | ## Create `CodeEditor` composable 41 | 42 | Now, we will create `CodeEditor` composable, which will be composed with `AndroidView`. In this composable, it will accept a `state` parameter which is associated with `CodeEditorState`. 43 | 44 | ```kotlin 45 | @Composable 46 | fun CodeEditor( 47 | modifier: Modifier = Modifier, 48 | state: CodeEditorState 49 | ) { 50 | // ... 51 | } 52 | ``` 53 | 54 | ### Set the factory for `CodeEditor` 55 | 56 | We will need a `Context` to define a `CodeEditor`. 57 | 58 | ```kotlin 59 | private fun setCodeEditorFactory( 60 | context: Context, 61 | state: CodeEditorState 62 | ): CodeEditor { 63 | val editor = CodeEditor(context) 64 | editor.apply { 65 | setText(state.content) 66 | // ... 67 | } 68 | state.editor = editor 69 | return editor 70 | } 71 | ``` 72 | 73 | Once we finished creating the factory, we now can define it with `remember` composable function. 74 | 75 | ```kotlin 76 | @Composable 77 | fun CodeEditor( 78 | modifier: Modifier = Modifier, 79 | state: CodeEditorState 80 | ) { 81 | val context = LocalContext.current 82 | val editor = remember { 83 | setCodeEditorFactory( 84 | context = context, 85 | state = state 86 | ) 87 | } 88 | AndroidView( 89 | factory = { editor }, 90 | modifier = modifier, 91 | onRelease = { 92 | it.release() 93 | } 94 | ) 95 | // ... 96 | } 97 | ``` 98 | 99 | ### Set `LaunchedEffect` for `CodeEditor`'s states 100 | 101 | We need to use `LaunchedEffect` to trigger when there are states of `CodeEditor` changed. 102 | 103 | ```kotlin 104 | LaunchedEffect(key1 = state.content) { 105 | state.editor?.setText(state.content) 106 | } 107 | ``` 108 | 109 | ## Using the `CodeEditor` composable 110 | 111 | After we finished implementing the `CodeEditor` composable, we can use it in our apps now. First of all, **it is highly recommend** to create a `CodeEditorState` in the `ViewModel`. 112 | 113 | For example, in the `MainScreen`, we will create `MainViewModel`, in this viewmodel, we will define the `CodeEditorState` here. 114 | 115 | ```kotlin 116 | class MainViewModel : ViewModel() { 117 | val editorState by mutableStateOf( 118 | CodeEditorState() 119 | ) 120 | } 121 | ``` 122 | 123 | Then, for the `MainScreen` composable, make sure you need to adjust the `Modifier` of `CodeEditor` as it is neccessary. 124 | 125 | ```kotlin 126 | @Composable 127 | fun MainScreen( 128 | viewModel: MainViewModel = viewModel() 129 | ) { 130 | Column { 131 | CodeEditor( 132 | modifier = Modifier 133 | .fillMaxSize(), 134 | state = viewModel.editorState 135 | ) 136 | } 137 | } 138 | ``` 139 | 140 | ::: warning WARNING 141 | If there are composables on the bottom of the `CodeEditor`, please set `Modifier.weight(1f)` instead of `Modifier.fillMaxSize()`. Otherwise, the `CodeEditor` will just dominate entire screen. 142 | ::: 143 | 144 | ## End 145 | 146 | `CodeEditor` is the only widget that we need to use `AndroidView`. As for the other widgets like `SymbolInputView`, they can be fully implemented with composables. 147 | 148 | --- 149 | 150 | That's all. I don't know if this is a good practice to attempt Sora Editor's `CodeEditor` in Jetpack Compose, but I hope you will be inspired through this guide. Thanks for reading. -------------------------------------------------------------------------------- /docs/zh/guide/events-and-components.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | 5 | # 事件和组件 6 | 7 | ## Event事件 8 | 9 | `Event`用于通知编辑器中的某些变化。由于编辑器会覆盖某些输入处理逻辑,所以请确保您使用的是编辑器的事件系统,而不是`View`的监听器。如果您使用这些监听器,则可能不会收到回调。 10 | 11 | ### 事件类型 12 | 13 | 常用: 14 | * `ClickEvent`:执行单击时触发 15 | * `DoubleClickEvent`:在用户双击视图时触发。此时首次单击会触发`ClickEvent`,第二次单击则不会。 16 | * `LongPressEvent`:长按视图时触发。 17 | * `ContentChangeEvent`:在调用`setText()`或编辑器中的当前文本发生更改时触发。 18 | 19 | ::: details 所有类型的事件 20 | * ClickEvent 21 | * DoubleClickEvent 22 | * LongPressEvent 23 | * ContentChangeEvent 24 | * EditorKeyEvent 25 | * KeyBindingEvent 26 | * ScrollEvent 27 | * SelectionChangeEvent 28 | * SideIconClickEvent 29 | * SnippetEvent 30 | * HandleStateChangeEvent 31 | * ColorSchemeUpdateEvent 32 | * PublishSearchResultEvent 33 | * EditorLanguageChangeEvent 34 | * EditorFormatEvent 35 | * EditorReleaseEvent 36 | * ImePrivateCommandEvent 37 | * BuildEditorInfoEvent 38 | * EditorFocusChangeEvent 39 | * EditorAttachStateChangeEvent 40 | * ContextClickEvent 41 | * HoverEvent 42 | * CreateContextMenuEvent 43 | ::: 44 | 45 | ### 订阅事件 46 | 47 | 通常,我们使用`CodeEditor#subscribeEvent`为某些类型的事件添加回调。 48 | 49 | 下面是一个订阅`ClickEvent`的示例。 50 | 51 | ::: code-group 52 | 53 | ```Kotlin Kotlin 54 | editor.subscribeEvent { event, unsubscribe -> 55 | // 执行内容 56 | } 57 | ``` 58 | 59 | ```Java Java 60 | editor.subscribeEvent(ClickEvent.class, (event, unsubscribe) -> { 61 | // 执行内容 62 | }); 63 | ``` 64 | ::: 65 | 66 | 如果您后续不打算在事件处理逻辑中取消订阅: 67 | 68 | ::: code-group 69 | 70 | ```Kotlin Kotlin 71 | editor.subscribeAlways { event -> 72 | // 执行内容 73 | } 74 | 75 | // 或者 76 | editor.subscribeAlways { 77 | // 执行内容 78 | } 79 | ``` 80 | 81 | ```Java Java 82 | editor.subscribeAlways(ClickEvent.class, (event) -> { 83 | // 执行内容 84 | }); 85 | ``` 86 | ::: 87 | 88 | ::: tip 注意 89 | 目前,您无法订阅抽象/超类的事件来处理具有相同超类的多种类型的事件。 90 | ::: 91 | 92 | ### 取消订阅事件 93 | 94 | 有时,我们不希望总是收到事件。您可以使用事件中给出的`Unsubscribe`对象自行取消订阅。 95 | 96 | 在下面的代码示例中,监听器将接收一次订阅事件。 97 | 98 | ::: code-group 99 | 100 | ```Kotlin Kotlin 101 | editor.subscribeEvent { event, unsubscribe -> 102 | // 执行内容 103 | // ... 104 | unsubsribe.unsubscribe() 105 | } 106 | ``` 107 | ```Java Java 108 | editor.subscribeEvent(ClickEvent.class, (event, unsubscribe) -> { 109 | // 执行内容 110 | // ... 111 | unsubscribe.unsubscribe(); 112 | }); 113 | ``` 114 | 115 | ::: 116 | 117 | 如果您想在事件回调之外取消订阅事件接收器,请使用您从`subscribeEvent`获得的对象。 118 | 119 | ::: code-group 120 | 121 | ```Kotlin Kotlin 122 | val receipt = editor.subscribeEvent { event, unsubscribe -> 123 | // 执行内容 124 | } 125 | // 可以在任意位置取消订阅 126 | receipt.unsubscribe() 127 | ``` 128 | 129 | ```Java Java 130 | var receipt = editor.subscribeEvent(ClickEvent.class, (event, unsubscribe) -> { 131 | // 执行内容 132 | }); 133 | // 可以在任意位置取消订阅 134 | receipt.unsubscribe(); 135 | ``` 136 | 137 | ::: 138 | 139 | ::: warning 请注意 140 | `receipt`用于在回调之外取消订阅事件。如果您正在处理事件,请使用给定的`Unsubscribe`对象。 141 | ::: 142 | 143 | ## 组件 144 | 145 | 组件是编辑器的一部分。大多数组件都依赖于事件系统,编辑器本身并不直接控制组件。它们可以随时被禁用或替换。 146 | 147 | ### 组件操作 148 | 149 | 您可以通过`CodeEditor#getComponent`获取组件对象。 150 | 151 | ::: code-group 152 | ```Kotlin Kotlin 153 | val component = editor.getComponent() 154 | ``` 155 | ```Java Java 156 | var component = editor.getComponent(EditorAutoCompletion.class); 157 | ``` 158 | ::: 159 | 160 | 禁用组件。 161 | 162 | ::: code-group 163 | ```Kotlin Kotlin 164 | component.isEnabled = false 165 | ``` 166 | ```Java Java 167 | component.setEnabled(false); 168 | ``` 169 | ::: 170 | 171 | ### 组件介绍 172 | 173 | #### 自动补全 174 | 175 | `EditorAutoCompletion`管理自动完成分析和补全候选窗口。 176 | 177 | 它检查是否适合在编辑器事件上显示完成,并将后台完成任务调度给`Language`。 178 | 179 |
Auto-Completion Preview
180 | 181 | #### 文本操作窗口 182 | 183 | `EditorTextActionWindow`管理文本操作的小面板,包括粘贴、复制、剪切、全选和长选。 184 | 185 | 当选择文本或用户单击插入选择时,将显示该面板。 186 | 187 |
Text Actions Preview
188 | 189 | #### 放大镜 190 | 191 | `Magnifier`由`EditorTouchEventHandler`控制。按住任何选择手柄时,将显示文本放大镜。 192 | 193 |
TMagnifier Preview
194 | 195 | #### 诊断工具提示 196 | 197 | 在进入诊断项目区域时,`EditorDiagnosticsTooltipWindow`将插入或选择文本时显示。它需要从您的Language实现中的`DiagnosticDetail`来获取诊断项目的详细信息。 198 | 199 | 工具提示窗口还允许用户对文本执行快速修复。(实验性) 200 | 201 | 202 |
Text Actions Preview
203 | 204 | #### 上下文菜单 205 | 206 | `EditorContextMenuCreator`帮助编辑器能够让用户在编辑器中执行鼠标右键单击时创建上下文菜单。 -------------------------------------------------------------------------------- /docs/guide/using-composeview-in-popupwindow.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | 5 | # Using ComposeView in PopupWindow 6 | 7 | `CodeEditor` supports a number of components namely `EditorAutoCompletion`, `EditorTextActionWindow` etc, when you want to customize the layout of them, you will have two approaches: 8 | 9 | 1. Using legacy XML to define the layouts 10 | 2. Using Compose to define the layout with `ComposeView` 11 | 12 | In this documentation, we will dive into the approach of using Compose to define the layout for `EditorTextActionWindow`. 13 | 14 | ## Challenges of attempting `ComposeView` in `PopupWindow` 15 | 16 | As the `EditorTextActionWindow` internally uses `PopupWindow`, and provides 17 | `setContentView()` to apply the view to the component. 18 | 19 | ::: danger ERROR 20 | However, if you directly put the Compose content in the `PopupWindow`, an error will throw. 21 | ```kotlin 22 | java.lang.IllegalStateException: ViewTreeLifecycleOwner not found from android.widget.PopupWindow$PopupDecorView{9dfea2f V.E...... R.....I. 0,0-0,0} 23 | at androidx.compose.ui.platform.WindowRecomposer_androidKt.createLifecycleAwareViewTreeRecomposer(WindowRecomposer.android.kt:242) 24 | at androidx.compose.ui.platform.WindowRecomposer_androidKt.access$createLifecycleAwareViewTreeRecomposer(WindowRecomposer.android.kt:1) 25 | ... 26 | ``` 27 | ::: 28 | 29 | By default, the `PopupWindow` cannot be worked with Compose. To solve this, we need a `FrameLayout` to be the parent layout of the `PopupWindow`, we then use this `FrameLayout` to contain the Compose content, and apply the `ViewTreeLifecycleOwner` and `ViewTreeSavedStateRegistryOwner` to the `FrameLayout`. 30 | 31 | ::: tip TIP 32 | We can directly retrieve the `ViewTreeLifecycleOwner` and `ViewTreeSavedStateRegistryOwner` via the `CompositionLocal`. 33 | 34 | ```kotlin 35 | val viewTreeLifecycleOwner = LocalViewTreeLifecycleOwner.current 36 | val viewTreeSavedStateRegistryOwner = LocalViewTreeSavedStateRegistry.current 37 | ``` 38 | ::: 39 | 40 | ## Define a `FrameLayout` 41 | 42 | We will use `android.R.id.content` for the content child of the `View` as it is neccessary to let Compose find the content child. 43 | 44 | ```kotlin 45 | val composeView = ComposeView(context).apply { 46 | setContent { 47 | // the Compose content... 48 | } 49 | } 50 | val parentView = FrameLayout(context).apply { 51 | id = android.R.id.content 52 | setViewTreeLifecycleOwner(viewTreeLifecycleOwner) 53 | setViewTreeSavedStateRegistryOwner(viewTreeSavedStateRegistryOwner) 54 | layoutParams = FrameLayout.LayoutParams( 55 | ViewGroup.LayoutParams.WRAP_CONTENT, 56 | ViewGroup.LayoutParams.WRAP_CONTENT 57 | ) 58 | addView(composeView) 59 | } 60 | ``` 61 | 62 | ## Complete the `EditorTextActionWindow` layout 63 | 64 | Here is the example of customizing the layout for `EditorTextActionWindow` in Compose. 65 | 66 | ```kotlin 67 | data class EditorTextActionItem( 68 | val label: String, 69 | val icon: ImageVector 70 | ) 71 | ``` 72 | 73 | ```kotlin 74 | val actionItems = listOf( 75 | EditorTextActionItem( 76 | label = "Select all", 77 | icon = /* ... */ 78 | ), 79 | EditorTextActionItem( 80 | label = "Copy", 81 | icon = /* ... */ 82 | ) 83 | EditorTextActionItem( 84 | label = "Paste", 85 | icon = /* ... */ 86 | ) 87 | // ... 88 | ) 89 | ``` 90 | 91 | ```kotlin 92 | @Composable 93 | fun EditorTextActionWindow( 94 | modifier: Modifier = Modifier, 95 | items: List, 96 | onItemClick: (EditorTextActionItem) -> Unit 97 | ): FrameLayout { 98 | val context = LocalContext.current 99 | val viewTreeLifecycleOwner = LocalViewTreeLifecycleOwner.current 100 | val viewTreeSavedStateRegistryOwner = LocalViewTreeSavedStateRegistry.current 101 | val composeView = ComposeView(context).apply { 102 | setContent { 103 | EditorTextActionContent(modifier, items, onItemClick) 104 | } 105 | } 106 | val parentView = FrameLayout(context).apply { 107 | id = android.R.id.content 108 | setViewTreeLifecycleOwner(viewTreeLifecycleOwner) 109 | setViewTreeSavedStateRegistryOwner(viewTreeSavedStateRegistryOwner) 110 | layoutParams = FrameLayout.LayoutParams( 111 | ViewGroup.LayoutParams.WRAP_CONTENT, 112 | ViewGroup.LayoutParams.WRAP_CONTENT 113 | ) 114 | addView(composeView) 115 | } 116 | return parentView 117 | } 118 | 119 | @Composable 120 | private fun EditorTextActionContent( 121 | modifier: Modifier = Modifier, 122 | items: List, 123 | onItemClick: (EditorTextActionItem) -> Unit 124 | ) { 125 | Row(modifier) { 126 | items.forEach { item -> 127 | IconButton( 128 | onClick = { onItemClick(item) } 129 | ) { 130 | Icon( 131 | imageVector = item.icon, 132 | contentDescription = item.label 133 | ) 134 | } 135 | } 136 | } 137 | } 138 | ``` 139 | 140 | Finally, apply the layout into `EditorTextActionWindow`. 141 | 142 | ```kotlin 143 | editor.getComponent().setContentView(parentView) 144 | ``` -------------------------------------------------------------------------------- /docs/reference/keybindings.md: -------------------------------------------------------------------------------- 1 | # Keybindings 2 | When working with a physical keyboard, you can use key bindings for performing various text actions. 3 | 4 | The editor provides support for some key bindings by default. The currently supported key bindings are mostly similar to Android Studio/IntelliJ IDEA. 5 | ## Built-in Keybindings 6 | The following key bindings are currently supported by the editor : 7 | 8 | | Keybinding | Description | 9 | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | 10 | | `Ctrl + A` | Select all. | 11 | | `Ctrl + X` | If no content is selected, cuts the current line. Otherwise, performs the usual cut operation. | 12 | | `Ctrl + C` | If no content is selected, selects and copies the current line. Otherwise, performs the usual copy operation. | 13 | | `Ctrl + V` | The usual paste action. | 14 | | `Ctrl + Z` | Undo the last action. | 15 | | `Ctrl + R` | Redo the last action. | 16 | | `Ctrl + D` | If content is selected, duplicates the selected content else duplicates the current line. | 17 | | `Ctrl + W` | Selects the word at the left selection handle. | 18 | | `Ctrl + Left` | Move to word start. If the cursor is already at the current word's start, moves the cursor to previous word's start, skipping whitespaces. | 19 | | `Ctrl + Right` | Move to word end. If the cursor is already at the current word's end, moves the cursor to next word's end, skipping whitespaces. | 20 | | `Ctrl + Up` | Scroll up by one row. | 21 | | `Ctrl + Down` | Scroll down by one row. | 22 | | `Ctrl + Home` | Move the cursor to the beginning of content. | 23 | | `Ctrl + End` | Move the cursor to the end of content. | 24 | | `Ctrl + PgUp` | Move the cursor to the page top. | 25 | | `Ctrl + PgDn` | Move the cursor to the page bottom. | 26 | | `Ctrl + Enter` | Split line. If content is selected, deletes the selected content then splits the line. | 27 | | `Ctrl + Shift + Left` | Same as `Ctrl+Left`, but starts or updates the selection. | 28 | | `Ctrl + Shift + Right` | Same as `Ctrl+Right`, but starts or updates the selection. | 29 | | `Ctrl + Shift + Up` | Move the current line (or all selected lines) up by one line. | 30 | | `Ctrl + Shift + Down` | Move the current line (or all selected lines) down by one line. | 31 | | `Ctrl + Shift + Home` | Same as `Ctrl+Home`, but starts or updates the selection. | 32 | | `Ctrl + Shift + End` | Same as `Ctrl+End`, but starts or updates the selection. | 33 | | `Ctrl + Shift + PgUp` | Move the cursor to the page top with selection. | 34 | | `Ctrl + Shift + PgDn` | Move the cursor to the page bottom with selection. | 35 | | `Ctrl + Alt + Enter` | Start a new line before current line. | 36 | | `Ctrl + Shift + J` | Join current line and next line. | 37 | | `Shift + Enter` | Start a new line. | 38 | | `Selection + TAB` | If the text is selected, pressing the `TAB` key indents all selected lines. | 39 | | `Shift + TAB` | Unindents the current line. If the text is selected, unindents all the selected lines. | 40 | 41 | ## Custom Keybindings 42 | You can subscribe 43 | to [`KeyBindingEvent`](https://github.com/Rosemoe/sora-editor/blob/main/editor/src/main/java/io/github/rosemoe/sora/event/KeyBindingEvent.java) 44 | and add your own key bindings. You can even override the default key bindings and perform actions of 45 | your own. -------------------------------------------------------------------------------- /docs/guide/events-and-components.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # Events and Components 5 | ## Event 6 | `Event` is delivered to notify certain changes in the editor. Make sure you use the event system instead of the listeners in `View`, because some input handling logic is overriden by the editor. You may not receive the callback if you use those listeners. 7 | ### Types of Event 8 | Frequently used: 9 | * `ClickEvent`: triggered when a single click is performed. 10 | * `DoubleClickEvent`: triggered when the user double-clicks the view. Note that in this case, the first click triggers `ClickEvent`, while the second click not. 11 | * `LongPressEvent`: triggered when the view is long pressed. 12 | * `ContentChangeEvent`: trigger when `setText()` is called or current text in editor changes. 13 | ::: details All Types of Event 14 | * ClickEvent 15 | * DoubleClickEvent 16 | * LongPressEvent 17 | * ContentChangeEvent 18 | * EditorKeyEvent 19 | * KeyBindingEvent 20 | * ScrollEvent 21 | * SelectionChangeEvent 22 | * SideIconClickEvent 23 | * SnippetEvent 24 | * HandleStateChangeEvent 25 | * ColorSchemeUpdateEvent 26 | * PublishSearchResultEvent 27 | * EditorLanguageChangeEvent 28 | * EditorFormatEvent 29 | * EditorReleaseEvent 30 | * ImePrivateCommandEvent 31 | * BuildEditorInfoEvent 32 | * EditorFocusChangeEvent 33 | * EditorAttachStateChangeEvent 34 | * ContextClickEvent 35 | * HoverEvent 36 | * CreateContextMenuEvent 37 | ::: 38 | ### Subscribe Event 39 | Usually, we use `CodeEditor#subscribeEvent` to add callbacks for certain type of event. 40 | 41 | Here is an example for subscribing `ClickEvent`. 42 | ::: code-group 43 | 44 | ```Kotlin Kotlin 45 | editor.subscribeEvent { event, unsubscribe -> 46 | // Handle the event 47 | } 48 | ``` 49 | 50 | ```Java Java 51 | editor.subscribeEvent(ClickEvent.class, (event, unsubscribe) -> { 52 | // Handle the event 53 | }); 54 | ``` 55 | ::: 56 | 57 | If you are not to unsubscribe in event handling logic: 58 | ::: code-group 59 | 60 | ```Kotlin Kotlin 61 | editor.subscribeAlways { event -> 62 | // Handle the event 63 | } 64 | 65 | // Alternatively 66 | editor.subscribeAlways { 67 | // Handle the event 68 | } 69 | ``` 70 | 71 | ```Java Java 72 | editor.subscribeAlways(ClickEvent.class, (event) -> { 73 | // Handle the event 74 | }); 75 | ``` 76 | ::: 77 | 78 | ::: tip NOTE 79 | Currently, you are unable to subscribe abstract/super events to handle several types of event with common super class. 80 | ::: 81 | ### Unsubscribe Event 82 | Sometimes, we do not want to always receive the event. 83 | You can use the `Unsubscribe` object given on event to unsubscribe yourself. 84 | 85 | In the following code example, the listener will receive the subscribed event once. 86 | ::: code-group 87 | 88 | ```Kotlin Kotlin 89 | editor.subscribeEvent { event, unsubscribe -> 90 | // Handle the event 91 | // ... 92 | unsubsribe.unsubscribe() 93 | } 94 | ``` 95 | 96 | ```Java Java 97 | editor.subscribeEvent(ClickEvent.class, (event, unsubscribe) -> { 98 | // Handle the event 99 | // ... 100 | unsubscribe.unsubscribe(); 101 | }); 102 | ``` 103 | 104 | ::: 105 | If you want to unsubscribe the event receiver outside the event callback, please use the receipt you get from `subscribeEvent`. 106 | ::: code-group 107 | 108 | ```Kotlin Kotlin 109 | val receipt = editor.subscribeEvent { event, unsubscribe -> 110 | // Handle the event 111 | } 112 | // Unsubscribe anywhere 113 | receipt.unsubscribe() 114 | ``` 115 | 116 | ```Java Java 117 | var receipt = editor.subscribeEvent(ClickEvent.class, (event, unsubscribe) -> { 118 | // Handle the event 119 | }); 120 | // Unsubscribe anywhere 121 | receipt.unsubscribe(); 122 | ``` 123 | 124 | ::: 125 | 126 | ::: warning BE CAREFUL 127 | The receipt is used to unsubscribe the event outside the callback. If you are handling the event, please use the `Unsubscribe` object given. 128 | ::: 129 | ## Components 130 | Componets are a part of editor. Most components rely on the event system but editor itself does not control the components directly. They can be disabled or replaced. 131 | ### Component Actions 132 | You can get a component by `CodeEditor#getComponent` with its class. 133 | ::: code-group 134 | 135 | ```Kotlin Kotlin 136 | val component = editor.getComponent() 137 | ``` 138 | 139 | ```Java Java 140 | var component = editor.getComponent(EditorAutoCompletion.class); 141 | ``` 142 | 143 | ::: 144 | Components can be disabled. 145 | ::: code-group 146 | 147 | ```Kotlin Kotlin 148 | component.isEnabled = false 149 | ``` 150 | 151 | ```Java Java 152 | component.setEnabled(false); 153 | ``` 154 | 155 | ::: 156 | ### Components Introduction 157 | #### Auto Completion 158 | `EditorAutoCompletion` manages auto-completion analysis and the completion windows. 159 | 160 | It checks if it is suitable to show the completion on editor events, and dispatches background completion task to the `Language`. 161 | 162 |
Auto-Completion Preview
163 | 164 | #### Text Action Window 165 | `EditorTextActionWindow` manages the small panel for text actions, including paste, copy, cut, select-all and long-select. 166 | 167 | The panel is shown when text is selected or the user clicks on the insert selection. 168 | 169 |
Text Actions Preview
170 | 171 | #### Magnifier 172 | `Magnifier` is controlled by `EditorTouchEventHandler`. Text magnifier is shown when any selection handle is held. 173 | 174 |
TMagnifier Preview
175 | 176 | #### Diagnostic Tooltip 177 | `EditorDiagnosticsTooltipWindow` is shown when insert selection enters a region of diagnostics item. It requires `DiagnosticDetail` from your language implementation for detailed information of the diagnostic item. 178 | 179 | The tooltip window also allows the user to perform quickfixes on the text. (experimental) 180 | 181 | 182 |
Text Actions Preview
183 | 184 | #### Context Menu 185 | `EditorContextMenuCreator` helps the editor to create context menu when mouse right-clicks in editor. -------------------------------------------------------------------------------- /docs/ja/guide/using-language.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # 言語 5 | 言語は、構文分析、自動補完、自動インデントなどの言語固有の機能を提供する Sora Editor のインターフェイスです。 6 | 7 | 単一の `Language` インスタンスは 1 つのエディター インスタンスのみに使用する必要があります。 そして、エディタ インスタンスが解放されるか、新しい `Language` インスタンスが設定されると、自動的に破棄されます。 8 | 9 | `CodeEditor#setEditorLanguage` を使用して、新しい `Language` を適用できます。 デフォルトでは、エディターは組み込みの `EmptyLanguage` を使用し、分析は実行されません。 したがって、構文ハイライトやその他の言語機能は利用できません。 10 | 11 | プログラミング言語の分析と構文ハイライトを設定するためのユニバーサル言語実装が提供されています。 `language-java` モジュールは単純なトークンベースの Java 構文ハイライト専用であることに注意してください。 12 | ## 言語モジュールを使用する 13 | 言語モジュールを使用する前に、それがプロジェクトにインポートされていることを確認してください。 14 | ### language-textmate 15 | このモジュールは、[TextMate](https://github.com/textmate/textmate) 文法を使用して、テキストのトークン化とさまざまなプログラミング言語のハイライトを支援します。 TextMate は、[Visual Studio Code](https://github.com/microsoft/vscode) および [Eclipse](https://github.com/eclipse/tm4e) の構文ハイライトにも使用されます。 ほとんどのライブラリ インテグレータは、 `Language` 実装を自分で作成する代わりに、このモジュールを使用することを好みます。 16 | 17 | エディターに TextMate を使用するには、以下の手順に従ってください。 18 | #### 言語構文と構成を見つける 19 | TextMate はさまざまな言語をサポートしており、構文ハイライト ルールは `*.tmLanguage` PLIST ファイルまたは `*.tmLanguage.json` JSON ファイルによって定義されます。 これらの TextMate ルール ファイル (別名 `syntaxes`) と、オプションでターゲット言語の言語設定ファイル (`*. language-configuration.json`) が必要です。 20 | 21 | これらのファイルは次の場所にあります。 22 | * [TM4E 言語パック](https://github.com/eclipse/tm4e/tree/25e7fbe39c02644ca5d541d20a2c601791af7b8d/org.eclipse.tm4e.language_pack/syntaxes) 23 | * [VSCode 拡張機能](https://github.com/microsoft/vscode/tree/4f2ff19ecacffa0aa4874db4d63ed4e899d98431/extensions) 24 | #### テーマを見つける 25 | TextMate は TextMate テーマと一緒に使用する必要があります。 また、[VSCode Extensions](https://github.com/microsoft/vscode/tree/4f2ff19ecacffa0aa4874db4d63ed4e899d98431/extensions) からテーマ JSON ファイルを見つける必要があります。 26 | `theme-*` パターンで名前が付けられたフォルダーがいくつかあります。 これらのフォルダーは、VSCode 組み込み TextMate テーマ用です。 27 | #### 言語レジストリの準備 28 | TextMate では複数の言語を読み込むことができます。 後でロードできるように `languages.json` を準備する必要があります。 たとえば、アセット ディレクトリは次のとおりです: 29 | ```Text 30 | . 31 | ├─ textmate 32 | │ ├─ java 33 | │ │ ├─ syntaxes 34 | │ │ │ └─ java.tmLanguage.json 35 | │ │ └─ language-configuration.json 36 | │ └─ kotlin 37 | │ ├─ syntaxes 38 | │ │ └─ Kotlin.tmLanguage 39 | │ └─ language-configuration.json 40 | └─ language.json 41 | ``` 42 | `language.json` はつぎのとおりです: 43 | ```JSON 44 | { 45 | "languages": [ 46 | { 47 | "grammar": "textmate/java/syntaxes/java.tmLanguage.json", 48 | "name": "java", 49 | "scopeName": "source.java", 50 | "languageConfiguration": "textmate/java/language-configuration.json" 51 | }, 52 | { 53 | "grammar": "textmate/kotlin/syntaxes/Kotlin.tmLanguage", 54 | "name": "kotlin", 55 | "scopeName": "source.kotlin", 56 | "languageConfiguration": "textmate/kotlin/language-configuration.json" 57 | } 58 | ] 59 | } 60 | ``` 61 | `name` はカスタムで、`scopeName` は構文ファイルのルート スコープです。 62 | 63 | インジェクション言語を使用できる言語については、[デモアプリ](https://github.com/Rosemoe/sora-editor/blob/main/app/src/main/assets/textmate/langages.json)の HTML サンプルを参照してください。 64 | #### ロード構文とテーマ 65 | エディターで TextMate を使い始める前に、まず TextMate 用のデータを準備する必要があります。 **これらの手順は、TextMate を使用するエディタの数に関係なく、1 回だけ実行されます。** 66 | 67 | APK アセットから textmate ファイルをロードするとします。 まず、TextMate の内部ファイル アクセス用に `FileResolver` を追加する必要があります。 68 | ::: code-group 69 | 70 | ```Kotlin Kotlin 71 | FileProviderRegistry.getInstance().addFileProvider( 72 | AssetsFileResolver( 73 | applicationContext.assets // アプリケーションコンテキストを使用する 74 | ) 75 | ) 76 | ``` 77 | 78 | ```Java Java 79 | FileProviderRegistry.getInstance().addFileProvider( 80 | new AssetsFileResolver( 81 | getApplicationContext().getAssets() // アプリケーションコンテキストを使用する 82 | ) 83 | ) 84 | ``` 85 | 86 | ::: 87 | 次に、テーマがロードされるはずです。 以下のコードは、単一のテーマをエディターにロードする方法を示しています。 88 | ::: code-group 89 | 90 | ```Kotlin Kotlin 91 | val themeRegistry = ThemeRegistry.getInstance() 92 | val name = "quietlight" // テーマの名前 93 | val themeAssetsPath = "textmate/$name.json" 94 | themeRegistry.loadTheme( 95 | ThemeModel( 96 | IThemeSource.fromInputStream( 97 | FileProviderRegistry.getInstance().tryGetInputStream(themeAssetsPath), themeAssetsPath, null 98 | ), 99 | name 100 | ).apply { 101 | // テーマが暗い場合 102 | // isDark = true 103 | } 104 | ) 105 | ``` 106 | 107 | ```Java Java 108 | var themeRegistry = ThemeRegistry.getInstance(); 109 | var name = "quietlight"; // テーマの名前 110 | var themeAssetsPath = "textmate/" + name + ".json"; 111 | var model = new ThemeModel( 112 | IThemeSource.fromInputStream( 113 | FileProviderRegistry.getInstance().tryGetInputStream(themeAssetsPath), themeAssetsPath, null 114 | ), 115 | name 116 | ); 117 | // テーマが暗い場合 118 | // model.setDark(true); 119 | themeRegistry.loadTheme(model); 120 | ``` 121 | 122 | ::: 123 | 次に、TextMate のアクティブなテーマを選択します。 TextMate は、レジストリを使用してグローバル カラー スキームを管理します。 124 | ::: code-group 125 | 126 | ```Kotlin Kotlin 127 | ThemeRegistry.getInstance().setTheme("your-theme-name") 128 | ``` 129 | 130 | ```Java Java 131 | ThemeRegistry.getInstance().setTheme("your-theme-name"); 132 | ``` 133 | 134 | ::: 135 | 最後に、言語の構文と構成をロードします。 136 | 137 | ::: code-group 138 | 139 | ```Kotlin Kotlin 140 | GrammarRegistry.getInstance().loadGrammars("textmate/languages.json") 141 | ``` 142 | 143 | ```Java Java 144 | GrammarRegistry.getInstance().loadGrammars("textmate/languages.json"); 145 | ``` 146 | 147 | ::: 148 | 149 | #### エディターの設定 150 | エディターの配色を設定します。 `TextMateColorScheme` がエディタに適用されていない場合、TextMate の構文ハイライト結果の色は透明になります。 151 | ::: code-group 152 | 153 | ```Kotlin Kotlin 154 | editor.colorScheme = TextMateColorScheme.create(ThemeRegistry.getInstance()) 155 | ``` 156 | 157 | ```Java Java 158 | editor.setColorScheme(TextMateColorScheme.create(ThemeRegistry.getInstance())); 159 | ``` 160 | 161 | ::: 162 | エディタの言語を設定します。 163 | ::: code-group 164 | 165 | ```Kotlin Kotlin 166 | val languageScopeName = "source.java" // ターゲット言語のスコープ名 167 | val language = TextMateLanguage.create( 168 | languageScopeName, true /* オートコンプリートを有効にする場合は true */ 169 | ) 170 | editor.setEditorLanguage(language) 171 | ``` 172 | 173 | ```Java Java 174 | var languageScopeName = "source.java"; // ターゲット言語のスコープ名 175 | var language = TextMateLanguage.create( 176 | languageScopeName, true /* オートコンプリートを有効にする場合は true */ 177 | ); 178 | editor.setEditorLanguage(language); 179 | ``` 180 | 181 | ::: 182 | これですべての設定が完了しました。おめでとう! 183 | ### language-java 184 | Java 言語サポートは、トークンベースのハイライト、識別子のオートコンプリート、およびコード ブロック マーカーを提供します。 エディターをテストするための実験的な機能もいくつかあります。 185 | 186 | 機能は依然としてシンプルですが、その速度は他の複雑な言語分析に比べてかなり高速です。 187 | 188 | 言語を作成して適用するには、以下のコードを参照してください: 189 | ::: code-group 190 | 191 | ```Kotlin Kotlin 192 | editor.editorLanguage = JavaLanguage() 193 | ``` 194 | 195 | ```Java Java 196 | editor.setEditorLanguage(new JavaLanguage()); 197 | ``` 198 | 199 | ::: 200 | ### language-treesitter 201 | TreeSitter は、[Atom](https://github.com/atom/atom) と現在は [Zed](https://github.com/zed-industries/zed) の作成者によって開発され、2 つのコード エディターで使用されています。 。 TreeSitter は、パーサー生成ツールおよび増分解析ライブラリです。 202 | 203 | TreeSitter を使用すると、ソース ファイルの具体的な構文ツリーを構築し、ソース ファイルの編集に応じて構文ツリーを効率的に更新できます。 また、正確な構文の強調表示には構文ツリーを使用します。 204 | 205 | Java バインディング [android-tree-sitter](https://github.com/AndroidIDEOfficial/android-tree-sitter) を使用して、tree-sitter API を呼び出します。 206 | 207 | 読み進める前に、まずエディター フレームワークの [TextStyle](https://github.com/Rosemoe/sora-editor/blob/main/editor/src/main/java/io/github/rosemoe/sora/lang/styling/TextStyle.java) をチェックアウトすることを強くお勧めします。 208 | 209 | #### 言語を準備する 210 | 211 | 既存の言語実装を見つけることができます 212 | [android-tree-sitter](https://github.com/AndroidIDEOfficial/android-tree-sitter) より。 希望する言語が 213 | 欠けている場合は、Android 用の言語を自分で構築する必要があります。 214 | 215 | さらに、構文ツリーをクエリするための 4 つの `scm` ファイルが必要です。 216 | * 1.ハイライト用 217 | ほとんどの言語の「highlights.scm」は、TreeSitter 言語リポジトリにあります。 たとえば、Java 用のものは [こちら](https://github.com/tree-sitter/tree-sitter-java/tree/master/queries) です。 218 | * 2. コードブロック用(オプション) 219 | これは sora エディター固有のクエリです。 手順とサンプルについては、[こちら](https://github.com/Rosemoe/sora-editor/blob/main/app/src/main/assets/tree-sitter-queries/java/blocks.scm)を参照してください。 220 | * 3.ブラケット用(オプション) 221 | これは sora エディター固有のクエリです。 手順とサンプルについては、[こちら](https://github.com/Rosemoe/sora-editor/blob/main/app/src/main/assets/tree-sitter-queries/java/brackets.scm)を参照してください。 222 | * 4. ローカル変数の場合(オプション) 223 | ほとんどの言語の「locals.scm」は、[nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter/tree/master/queries) リポジトリにあります。 224 | 225 | 役立つリンク: 226 | * [TreeSitter](https://github.com/tree-sitter) 227 | * [TreeSitter ドキュメント](https://tree-sitter.github.io/tree-sitter/) 228 | * [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) 229 | * [Zed 言語](https://github.com/zed-industries/zed/tree/main/crates/zed/src/languages) -------------------------------------------------------------------------------- /docs/zh/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # 快速开始 5 | ## 要求 6 | 您的项目在引入[sora-editor](https://github.com/Rosemoe/sora-editor)库之前,请确保您的构建环境及配置满足以下要求: 7 | * 使用Gradle编译且JDK版本不低于17 8 | * 您模块的最低Android SDK版本至少为Android L(API 21) 9 | * 如果您需要使用[语言服务器协议](https://microsoft.github.io/language-server-protocol/),则要求至少为Android O(API 26) 10 | * 项目的编译兼容性和目标兼容性应是`JavaVersion.VERSION_17` 11 | ::: details 设置Java源代码兼容性和目标兼容性 12 | 13 | ::: code-group 14 | 15 | ```Kotlin{3-4,8-10} [Kotlin DSL] 16 | android { 17 | compileOptions { 18 | sourceCompatibility = JavaVersion.VERSION_17 19 | targetCompatibility = JavaVersion.VERSION_17 20 | } 21 | } 22 | // 如果您的应用使用Kotlin,请额外添加以下配置 23 | // kotlin { 24 | // jvmToolchain(17) 25 | // } 26 | ``` 27 | 28 | ```Groovy{3-4} [Groovy DSL] 29 | android { 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_17 32 | targetCompatibility JavaVersion.VERSION_17 33 | } 34 | } 35 | ``` 36 | 37 | ::: 38 | 39 | 40 | ::: details 使用非Gradle进行构建 41 | 42 | 编辑器的相关资源通过AAR文件进行分发,所以构建系统必须支持处理AAR文件。 43 | 44 | 如果您一定要使用非Gradle作为您项目的构建系统,我们将不会为您的构建问题提供任何帮助。 45 | 46 | ::: 47 | ## 添加依赖 48 | 49 | 最新版本: [![Maven Central](https://img.shields.io/maven-central/v/io.github.rosemoe/editor.svg?label=Maven%20Central)]((https://search.maven.org/search?q=io.github.rosemoe%20editor)) 50 | 51 | 添加sora-editor到您应用的依赖中: 52 | 53 | ::: code-group 54 | 55 | ```Kotlin{2-3} [Kotlin DSL] 56 | dependencies { 57 | implementation(platform("io.github.rosemoe:editor-bom:<版本名>")) 58 | implementation("io.github.rosemoe:<模块名>") 59 | } 60 | ``` 61 | 62 | ```Groovy{2-3} [Groovy DSL] 63 | dependencies { 64 | implementation(platform("io.github.rosemoe:editor-bom:<版本名>")) 65 | implementation 'io.github.rosemoe:<模块名>' 66 | } 67 | ``` 68 | 69 | ::: 70 | 71 | 请将`<版本名>`和`<模块名>`替换为正确的版本名称和模块名称。你可以添加多个模块到您的项目中。 72 | 73 | 以下是一个在编辑器中使用TextMate语法高亮的示例,请根据您的实际情况引入: 74 | 75 | ::: code-group 76 | 77 | ```Kotlin{2-4} [Kotlin DSL] 78 | dependencies { 79 | implementation(platform("io.github.rosemoe:editor-bom:0.24.1")) 80 | implementation("io.github.rosemoe:editor") 81 | implementation("io.github.rosemoe:language-textmate") 82 | } 83 | ``` 84 | 85 | ```Groovy{2-4} [Groovy DSL] 86 | dependencies { 87 | implementation(platform("io.github.rosemoe:editor-bom:0.24.1")) 88 | implementation 'io.github.rosemoe:editor' 89 | implementation 'io.github.rosemoe:language-textmate' 90 | } 91 | ``` 92 | 93 | ```Kotlin{2-4} [Kotlin DSL(不使用bom)] 94 | dependencies { 95 | val editorVersion = "0.24.1" 96 | implementation("io.github.rosemoe:editor:$editorVersion") 97 | implementation("io.github.rosemoe:language-textmate:$editorVersion") 98 | } 99 | ``` 100 | 101 | ```Groovy{2-4} [Groovy DSL(不使用bom)] 102 | dependencies { 103 | def editorVersion = '0.24.1' 104 | implementation 'io.github.rosemoe:editor:$editorVersion' 105 | implementation 'io.github.rosemoe:language-textmate:$editorVersion' 106 | } 107 | ``` 108 | 109 | ::: 110 | 111 | ::: tip 注意 112 | 113 | 您可以通过上面的徽章中得知最新的版本名称,也可以前往我们的GitHub [Releases](https://github.com/Rosemoe/sora-editor/releases)页面获取完整的版本列表。 114 | 115 | 当前可供使用的模块有: `editor`、`editor-lsp`、`language-java`, `language-textmate`以及`language-treesitter`。 116 | 请参考下面的表格获取对应模块的相关信息。 117 | 118 | ::: 119 | 120 | ### 🛠️可用模块 121 | 122 | | 模块 | 介绍 | 123 | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 124 | | editor | 包含编辑器的核心框架。 | 125 | | editor-lsp | 可以使用语言服务器协议(简称LSP)创建语言的便捷工具库。 | 126 | | language-java | 包含Java高亮和自动补全的语言库。 | 127 | | language-textmate | 一个高级的高亮分析库。你可以借助它来加载textmate语言配置文件并应用于本编辑器。 内部实现来自[tm4e](https://github.com/eclipse/tm4e)。 | 128 | | language-treesitter | 为编辑器提供[tree-sitter](https://tree-sitter.github.io/tree-sitter/)支持。tree-sitter可用于快速、增量地将代码转换 成抽象语法树,以便您向用户提供精确的高亮和自动补全功能。注意此模块仅提供了转换和高亮支持。感谢[android-tree-sitter](https://github.com/AndroidIDEOfficial/android-tree-sitter/)项目提供的Java绑定库。 | 129 | 130 | | oniguruma-native | 用于 TextMate 的正则表达式库。默认不使用。 | 131 | 132 | ### 🚧快照构建 133 | 134 | 通常情况下我们建议使用[正式发布的版本](https://github.com/Rosemoe/sora-editor/releases)。但有时候您可能需要使用最新的构建版本以取得最新的错误修复和功能更新。 135 | 136 | ::: details 如何使用快照构建 137 | 138 | 快照版本在存储库推送时自动发布。您可以将当前发布的版本名称和 `-SNAPSHOT` 组合在一起,得到快照版本名称。 139 | 140 | 举个例子, 如果目前最新正式发布的版本是 `0.24.1`,则可以将 `0.24.1-SNAPSHOT` 作为版本号导入快照版本到您的项目中。 141 | 142 | 需要注意的是,使用快照版本您需要额外添加一个maven存储库: 143 | ```Kotlin{3} 144 | repositories { 145 | // ... 146 | maven("https://central.sonatype.com/repository/maven-snapshots") 147 | } 148 | ``` 149 | 150 | 由于 Central Portal 的限制,快照版本仅会保留 90 天。 151 | 152 | ::: 153 | 154 | ## 为TextMate配置脱糖 155 | 156 | 如果您的项目使用了`language-textmate`模块,并且想要在Android 13(API 33)以下的设备上运行您的应用,您**必须**启用[脱糖](https://developer.android.google.cn/studio/write/java8-support#library-desugaring)以避免兼容性问题。如果您已进行此操作,请看下一部分。 157 | 158 | 如果要启用脱糖,请按照以下说明配置您的**应用模块**。 159 | 160 | * 添加脱糖依赖 161 | ::: code-group 162 | 163 | ```Kotlin [Kotlin DSL] 164 | dependencies { 165 | coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") // [!code highlight] 166 | } 167 | ``` 168 | 169 | ```Groovy [Groovy DSL] 170 | dependencies { 171 | coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5' // [!code highlight] 172 | } 173 | ``` 174 | 175 | ::: 176 | 177 | * 添加编译选项 178 | ::: code-group 179 | 180 | ```Kotlin [Kotlin DSL] 181 | android { 182 | compileOptions { 183 | isCoreLibraryDesugaringEnabled = true // [!code highlight] 184 | } 185 | } 186 | ``` 187 | 188 | ```Groovy [Groovy DSL] 189 | android { 190 | compileOptions { 191 | coreLibraryDesugaringEnabled true // [!code highlight] 192 | } 193 | } 194 | ``` 195 | 196 | ::: 197 | 198 | ::: warning 注意 199 | 当您启用脱糖时,您应该通过如下两种方式构建用于发布的应用: 200 | * 菜单 `Build` | `Build Bundle(s) / APK(s)` | `Build APK(s)` 进行构建 201 | * 或者,运行Gradle任务 `assemble`。 例如,运行 `assembleDebug` 任务来生成`debug`变体的 APK 202 | 203 | 当您从运行按钮(或快捷键 `Shift+F10`)在特定设备上运行应用时,Android Studio 尝试加速解糖过程。它将生成目标设备 API 特定的 APK 文件,此安装包可能不能在其他设备上正常工作。 204 | 205 | 或者,您可以禁用 Android Studio 的这项功能来解决此问题。此项设置位于 `Experimental > Optimize build for target device API level only` 。 206 | ::: 207 | 208 | ## 创建组件 209 | 210 | 请确保您的项目中已经包含核心模块`editor`,并且您项目的Gradle相关文件已经成功同步。 211 | 212 | 主要的widget类名是`io.github.rosemoe.sora.widget.CodeEditor`。您可以通过XML或Java/Kotlin代码(推荐)创建代码编辑器,但是在XML中只能设置有限的属性。 213 | 214 | ### 在XML使用 215 | 216 | 在布局XML文件中声明编辑器: 217 | 218 | ```XML 219 | 225 | ``` 226 | 227 | 无需在XML的声明中设置`text`或者`textSize`。 228 | 229 | 有关其在XML中的用法,请参考[XML属性](/reference/xml-attributes)。 230 | 231 | ::: tip 注意 232 | 不建议编辑器宽度或高度是`wrap_content`。因为在这种情况下编辑文本时,编辑器会请求布局重新绘制,可能会导致性能问题或者卡顿。 233 | ::: 234 | 235 | ### 使用Java/Kotlin代码 236 | 237 | 如果我们处于`Activity`上下文或者`ViewGroup`中,只需要实例化一个编辑器对象并将其添加到任意的视图组中即可。 238 | 239 | ::: code-group 240 | 241 | ```Kotlin [Kotlin] 242 | val editor = CodeEditor(this) 243 | editor.setText("Hello, world!") // 设置文本 244 | editor.typefaceText = Typeface.MONOSPACE // 使用Monospace字体 245 | editor.nonPrintablePaintingFlags = 246 | CodeEditor.FLAG_DRAW_WHITESPACE_LEADING or CodeEditor.FLAG_DRAW_LINE_SEPARATOR or CodeEditor.FLAG_DRAW_WHITESPACE_IN_SELECTION // Show Non-Printable Characters 247 | vg.add(editor, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)) 248 | ``` 249 | 250 | ```Java [Java] 251 | var editor = new CodeEditor(this); 252 | editor.setText("Hello, world!"); // 设置文本 253 | editor.setTypefaceText(Typeface.MONOSPACE); // 使用Monospace字体 254 | editor.setNonPrintablePaintingFlags( 255 | CodeEditor.FLAG_DRAW_WHITESPACE_LEADING | CodeEditor.FLAG_DRAW_LINE_SEPARATOR | CodeEditor.FLAG_DRAW_WHITESPACE_IN_SELECTION); // Show Non-Printable Characters 256 | vg.add(editor, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 257 | ``` 258 | 259 | ::: 260 | 参考`CodeEditor`中声明的方法和`DirectAccessProps`的字段,您可以对编辑器进行更丰富的配置。 261 | 262 | ::: warning 请谨慎 263 | `DirectAccessProps`的字段并非在任何情况下都是立即生效的。在使用被`@InvalidateRequired`标记的字段后需要您显式的调用编辑器的`invalidate()`。 264 | 265 | 您不应该使用被`@UnsupportedUserUsage`标记的字段,因为它们只能被内部使用。 266 | ::: 267 | 268 | ## 释放组件 269 | 当一个`CodeEditor`实例不再被使用的时候,您应该调用其`release()`方法释放编辑器资源和为编辑器服务的后台线程。同时释放编辑器后不应使用此编辑器,避免出现意外错误。 270 | 271 | ::: code-group 272 | 273 | ```Kotlin Kotlin 274 | override fun onDestroy() { 275 | super.onDestroy() 276 | editor?.release() 277 | } 278 | ``` 279 | 280 | ```Java Java 281 | @Override 282 | protected void onDestroy() { 283 | super.onDestroy(); 284 | if (editor != null) { 285 | editor.release(); 286 | } 287 | } 288 | ``` 289 | 290 | ::: 291 | 292 | ## 更进一步 293 | 前往[语言](/language.md)和[配色方案](/color-scheme.md)为编辑器提供编程语言支持和自定义配色方案。 -------------------------------------------------------------------------------- /docs/ja/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # クイックスタート 5 | ## 要件 6 | [sora-editor](https://github.com/Rosemoe/sora-editor) ライブラリをプロジェクトに組み込む前に、環境とビルド構成が以下の要件を満たしていることを確認してください。 7 | * JDK 17 以降で Gradle を実行します、 8 | * モジュールの最小 Android SDK バージョンは Android L (API 21) 以上です、 9 | * [言語サーバー プロトコル](https://microsoft.github.io/language-server-protocol/) を使用する場合、Android O (API 26) 以上が必要となります、 10 | * プロジェクトの Java ソース互換性とターゲット互換性は `JavaVersion.VERSION_17` です。 11 | ::: details Java コンパイルとターゲットの互換性の設定 12 | 13 | ::: code-group 14 | 15 | ```Kotlin{3-4,8-10} [Kotlin DSL] 16 | android { 17 | compileOptions { 18 | sourceCompatibility = JavaVersion.VERSION_17 19 | targetCompatibility = JavaVersion.VERSION_17 20 | } 21 | } 22 | // アプリで Kotlin が使用されている場合 23 | // kotlin { 24 | // jvmToolchain(17) 25 | // } 26 | ``` 27 | 28 | ```Groovy{3-4} [Groovy DSL] 29 | android { 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_17 32 | targetCompatibility JavaVersion.VERSION_17 33 | } 34 | } 35 | ``` 36 | 37 | ::: 38 | 39 | 40 | ::: details 非 Gradle ビルド システムの場合 41 | 42 | エディターはリソースを使用し、AAR ファイルで配布されます。 ビルド システムは AAR ファイルの処理をサポートする必要があります。 43 | 44 | ビルド システムとして Gradle を使用していない場合、ビルドの問題に関連する情報は提供されません。 45 | 46 | ::: 47 | ## 依存関係の追加 48 | 49 | 最新版:[![Maven Central](https://img.shields.io/maven-central/v/io.github.Rosemoe.sora-editor/editor.svg?label=Maven%20Central)]((https://search.maven.org/search?q=io.github.Rosemoe.sora-editor%20editor)) 50 | 51 | sora-editor ライブラリをアプリの依存関係に追加してください: 52 | 53 | ::: code-group 54 | 55 | ```Kotlin{2-3} [Kotlin DSL] 56 | dependencies { 57 | implementation(platform("io.github.Rosemoe.sora-editor:bom:")) 58 | implementation("io.github.Rosemoe.sora-editor:") 59 | } 60 | ``` 61 | 62 | ```Groovy{2-3} [Groovy DSL] 63 | dependencies { 64 | implementation(platform("io.github.Rosemoe.sora-editor:bom:")) 65 | implementation 'io.github.Rosemoe.sora-editor:' 66 | } 67 | ``` 68 | 69 | ::: 70 | 71 | プレースホルダー `` と `` を正しいバージョン名とモジュール名に置き換えてください。 プロジェクトに複数のモジュールを追加できます。 72 | 73 | 以下は、エディターで構文を強調表示するために TextMate 文法を使用したい人向けの例です。 74 | 75 | ::: code-group 76 | 77 | ```Kotlin{2-4} [Kotlin DSL] 78 | dependencies { 79 | implementation(platform("io.github.Rosemoe.sora-editor:bom:0.23.2")) 80 | implementation("io.github.Rosemoe.sora-editor:editor") 81 | implementation("io.github.Rosemoe.sora-editor:language-textmate") 82 | } 83 | ``` 84 | 85 | ```Groovy{2-4} [Groovy DSL] 86 | dependencies { 87 | implementation(platform("io.github.Rosemoe.sora-editor:bom:0.23.2")) 88 | implementation 'io.github.Rosemoe.sora-editor:editor' 89 | implementation 'io.github.Rosemoe.sora-editor:language-textmate' 90 | } 91 | ``` 92 | 93 | ```Kotlin{2-4} [Kotlin DSL without bom] 94 | dependencies { 95 | val editorVersion = "0.23.2" 96 | implementation("io.github.Rosemoe.sora-editor:editor:$editorVersion") 97 | implementation("io.github.Rosemoe.sora-editor:language-textmate:$editorVersion") 98 | } 99 | ``` 100 | 101 | ```Groovy{2-4} [Groovy DSL without bom] 102 | dependencies { 103 | def editorVersion = '0.23.2' 104 | implementation 'io.github.Rosemoe.sora-editor:editor:$editorVersion' 105 | implementation 'io.github.Rosemoe.sora-editor:language-textmate:$editorVersion' 106 | } 107 | ``` 108 | 109 | ::: 110 | 111 | ::: tip NOTE 112 | 113 | 上のバッジから最新バージョン名を見つけるか、GitHub [リリース](https://github.com/Rosemoe/sora-editor/releases) ページにアクセスして完全なバージョンのリストを確認してください。 114 | 115 | 現在、利用可能なモジュール名は、`editor`、`editor-lsp`、`language-java`、`language-textmate`、および `language-treesitter` です。 116 | モジュールの詳細については、以下の表を確認してください。 117 | 118 | ::: 119 | 120 | ### 🛠️付属のモジュール 121 | 122 | | モジュール | 紹介 | 123 | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 124 | | editor | エディターのコア フレームワークが含まれています。 | 125 | | editor-lsp | Language Server Protocol (略して LSP) を使用して言語を作成するための便利なツールのライブラリです。 | 126 | | language-java | Java の強調表示とオートコンプリートを含む言語ライブラリ。 | 127 | | language-textmate | 高度なハイライト分析ライブラリ。これを使用して、textmate 言語構成ファイルをロードし、このエディターに適用できます。内部実装は [tm4e](https://github.com/eclipse/tm4e) から取得されます。 | 128 | | language-treesitter | エディターに [tree-sitter](https://tree-sitter.github.io/tree-sitter/) サポートを提供します。これを使用すると、コードを抽象構文ツリーに迅速かつ段階的に解析することができ、正確な強調表示と補完の提供に役立ちます。このモジュールはトランジションとハイライトのサポートのみを提供することに注意してください。[android-tree-sitter](https://github.com/AndroidIDEOfficial/android-tree-sitter/) プロジェクトによって提供される Java バインディング ライブラリを感謝します。 | 129 | ### 🚧スナップショット ビルド 130 | 131 | 通常は、[リリース済みバージョン](https://github.com/Rosemoe/sora-editor/releases) を使用することをお勧めします。 ただし、最新のバグ修正や機能強化のためにナイトリー ビルドを使用したい場合もあります。 132 | 133 | ::: details スナップショット ビルドの使用方法 134 | 135 | スナップショット バージョンは、リポジトリ プッシュ時に自動的に公開されます。 現在リリースされているバージョン名と短いコミット ハッシュを組み合わせて、 136 | スナップショット バージョン名を作成できます。 137 | 138 | たとえば、最新リリースのバージョン名が '0.21.1'、 139 | 短いコミット ハッシュが '97c4963' の場合、バージョン名 '0.21.1-97c4963-SNAPSHOT' を使用して、スナップショット バージョンをプロジェクトにインポートできます。 140 | 141 | 追加の Maven リポジトリを追加する必要があることに注意してください: 142 | ```Kotlin{3} 143 | repositories { 144 | // ... 145 | maven("https://s01.oss.sonatype.org/content/repositories/snapshots") 146 | } 147 | ``` 148 | 149 | ::: 150 | 151 | ## TextMate の脱糖(Desugar)を構成する 152 | 153 | プロジェクトで `language-textmate` モジュールを使用し、Android 13 (API 33) のデバイスでアプリケーションを実行したい場合は、互換性の問題を回避するためにコア ライブラリの脱糖を**有効にする必要があります**。 それ以外の場合は、次のセクションに進んでください。 154 | 155 | 脱糖を有効にするには、以下の手順に従って**アプリケーション モジュール**をセットアップしてください: 156 | 157 | * Desugar 依存関係を追加 158 | ::: code-group 159 | 160 | ```Kotlin [Kotlin DSL] 161 | dependencies { 162 | coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4") // [!code highlight] 163 | } 164 | ``` 165 | 166 | ```Groovy [Groovy DSL] 167 | dependencies { 168 | coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' // [!code highlight] 169 | } 170 | ``` 171 | 172 | ::: 173 | 174 | * コンパイルオプションの追加 175 | ::: code-group 176 | 177 | ```Kotlin [Kotlin DSL] 178 | android { 179 | compileOptions { 180 | isCoreLibraryDesugaringEnabled = true // [!code highlight] 181 | } 182 | } 183 | ``` 184 | 185 | ```Groovy [Groovy DSL] 186 | android { 187 | compileOptions { 188 | coreLibraryDesugaringEnabled true // [!code highlight] 189 | } 190 | } 191 | ``` 192 | 193 | ::: 194 | 195 | ## ウィジェットを作成する 196 | 197 | プロジェクトに `editor` モジュールが含まれていることを確認し、プロジェクトを Gradle ファイルと正常に同期してください。 198 | 199 | メインのウィジェット クラスは `io.github.rosemoe.sora.widget.CodeEditor` です。 コード エディターは、XML コードまたは Java/Kotlin コードによって作成できます。 200 | ### XML での使用 201 | レイアウト XML ファイルでエディターを宣言します: 202 | ```XML 203 | 209 | ``` 210 | XML宣言で `text` や `textSize` を設定する必要はありません。 211 | 212 | XML での使用法の詳細については、[XML 属性](/reference/xml-attributes) を参照してください。 213 | ::: tip NOTE 214 | エディターの幅または高さに `wrap_content` を使用することはお勧めできません。 その場合、テキストを編集するときに、編集者は再レイアウトを要求する必要があり、おそらくラグが発生します。 215 | ::: 216 | ### Java/Kotlin コードでの使用 217 | エディターを作成し、任意のビュー グループに追加するだけです。 任意の `Activity` コンテキストにいて、`vg` が `ViewGroup` インスタンスであると仮定します。 218 | ::: code-group 219 | ```Kotlin [Kotlin] 220 | val editor = CodeEditor(this) 221 | editor.setText("Hello, world!") // テキストの設定 222 | editor.typefaceText = Typeface.MONOSPACE // 等幅書体(Monospace)を使用する 223 | editor.nonPrintablePaintingFlags = 224 | CodeEditor.FLAG_DRAW_WHITESPACE_LEADING or CodeEditor.FLAG_DRAW_LINE_SEPARATOR or CodeEditor.FLAG_DRAW_WHITESPACE_IN_SELECTION // 印刷できない文字を表示する 225 | vg.add(editor, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)) 226 | ``` 227 | ```Java [Java] 228 | var editor = new CodeEditor(this); 229 | editor.setText("Hello, world!"); // テキストの設定 230 | editor.setTypefaceText(Typeface.MONOSPACE); // 等幅書体(Monospace)を使用する 231 | editor.setNonPrintablePaintingFlags( 232 | CodeEditor.FLAG_DRAW_WHITESPACE_LEADING | CodeEditor.FLAG_DRAW_LINE_SEPARATOR | CodeEditor.FLAG_DRAW_WHITESPACE_IN_SELECTION); // 印刷できない文字を表示する 233 | vg.add(editor, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 234 | ``` 235 | ::: 236 | 構成できるその他の属性については、`CodeEditor` のメソッドと `DirectAccessProps` のフィールドを参照してください。 237 | ::: warning ご注意! 238 | `DirectAccessProps` のすべてのフィールドが無効化されないと有効になるわけではありません。 `@InvalidateRequired` でマークされたフィールドを変更した後、エディターで `invalidate()` を呼び出します。 239 | 240 | `@UnsupportedUserUsage` でマークされたメソッドとフィールドは使用しないでください。 これらは内部アクセスに対して表示されます。 241 | ::: 242 | ## ウィジェットの解放 243 | `CodeEditor` インスタンスが使用されなくなった場合、その `release()` メソッドを呼び出して、リソースとエディターに提供されているバックグラウンド スレッドを**解放する必要があります**。 244 | エラーを避けるために、エディタをリリースした後はエディタを使用しないでください。 245 | 246 | ::: code-group 247 | 248 | ```Kotlin Kotlin 249 | override fun onDestroy() { 250 | super.onDestroy() 251 | editor?.release() 252 | } 253 | ``` 254 | 255 | ```Java Java 256 | @Override 257 | protected void onDestroy() { 258 | super.onDestroy(); 259 | if (editor != null) { 260 | editor.release(); 261 | } 262 | } 263 | ``` 264 | 265 | ::: 266 | ## 続くはどうしますか?... 267 | [言語](./using-language.md) および [カラー スキーム](./using-color-scheme.md) に移動して、エディターにプログラミング言語サポートとカスタム カラー スキームを装備します。 -------------------------------------------------------------------------------- /docs/zh/guide/using-language.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | 5 | # 语言支持 6 | 7 | Language是Sora Editor实现提供特定语言例如语法分析、自动补全和缩进等功能的接口。 8 | 9 | 单个`Language`实例应当只提供给一个编辑器使用,而且当一个编辑器实例被销毁或者设置新的`Language`实例时,旧的`Language` 10 | 将会自动销毁。 11 | 12 | 你可以调用`CodeEditor#setEditorLanguage`为编辑器设置一个新的`Language`。默认情况下,编辑器使用内置的`EmptyLanguage` 13 | 作为自己的语言,并且不进行任何分析,即语法高亮和其他语言功能均不可使用。 14 | 15 | 我们提供了一些通用的语言功能实现供您设置编程语言的分析和语法高亮显示。但请注意`language-java`模块只适用于简单的Java关键字的语法高亮。 16 | 17 | ## 使用语言模块 18 | 19 | 在使用语言模块之前,请确保已将其导入到项目中。 20 | 21 | ### language-textmate 22 | 23 | 此模块使用[textmate](https://github.com/textmate/textmate)语法来标记文本并实现各种编程语言的高亮显示。 24 | textmate在[Visual Studio Code](https://github.com/microsoft/vscode)和[Eclipse](https://github.com/eclipse/tm4e) 25 | 中也用于语法高亮。大多数情况下请使用这个模块实现语法高亮,而不是自己编写`Language`实现。 26 | 27 | 请按照以下步骤将textmate用于您的编辑器。 28 | 29 | #### 查找语言语法和配置 30 | 31 | textmate支持非常多的语言,它的语法高亮规则由名为`*.tmLanguage`的PLIST文件或者名为`*.tmLanguage.json`的JSON文件定义。 32 | 你需要textmate规则文件(又叫`语法`)和可选的语言配置文件(`*.language-configuration.json`)为您的语言提供高亮配置。 33 | 34 | 您可以在以下位置找到这些文件: 35 | 36 | * [TM4E语言包](https://github.com/eclipse/tm4e/tree/25e7fbe39c02644ca5d541d20a2c601791af7b8d/org.eclipse.tm4e.language_pack/syntaxes) 37 | * [VSCode扩展](https://github.com/microsoft/vscode/tree/4f2ff19ecacffa0aa4874db4d63ed4e899d98431/extensions) 38 | 39 | ::: tip 注意 40 | 41 | 当前的 TextMate 引擎对某些 TextMate 语法文件支持不完全。这是正则表达式库 [Joni](https://github.com/jruby/joni) 对这些语法文件中的正则表达式支持不完全导致的。 42 | 43 | 在进行高亮分析时,这些不受支持的正则表达式将用 `^$` 代替以避免产生错误。 44 | 45 | ::: 46 | #### 查找主题 47 | 48 | textmate必须和textmate主题搭配使用。你还需要从[VSCode Extensions](https://github.com/microsoft/vscode/tree/4f2ff19ecacffa0aa4874db4d63ed4e899d98431/extensions) 49 | 中查找您满意的主题JSON文件。 50 | 里面有一些文件夹的命名规则是`theme-*`。他们就是您要找的VSCode内置的textmate主题。 51 | 52 | #### 准备语言注册表 53 | 54 | textmate可以加载多种语言,所以我们需要提前准备一下`languages.json`。现在假设您的assets文件夹的目录结构如下: 55 | 56 | ```Text 57 | . 58 | ├─ textmate 59 | │ ├─ java 60 | │ │ ├─ syntaxes 61 | │ │ │ └─ java.tmLanguage.json 62 | │ │ └─ language-configuration.json 63 | │ └─ kotlin 64 | │ ├─ syntaxes 65 | │ │ └─ Kotlin.tmLanguage 66 | │ └─ language-configuration.json 67 | └─ language.json 68 | ``` 69 | 70 | 您的`language.json`内容如下: 71 | 72 | ```JSON 73 | { 74 | "languages": [ 75 | { 76 | "grammar": "textmate/java/syntaxes/java.tmLanguage.json", 77 | "name": "java", 78 | "scopeName": "source.java", 79 | "languageConfiguration": "textmate/java/language-configuration.json" 80 | }, 81 | { 82 | "grammar": "textmate/kotlin/syntaxes/Kotlin.tmLanguage", 83 | "name": "kotlin", 84 | "scopeName": "source.kotlin", 85 | "languageConfiguration": "textmate/kotlin/language-configuration.json" 86 | } 87 | ] 88 | } 89 | ``` 90 | 91 | `name`可以自行定义,`scopeName`是语法文件的作用域。 92 | 93 | 对于可以嵌入其他语言的语言,例如HTML和Markdown等标记语言。请参考适用于HTML的[示例应用](https://github.com/Rosemoe/sora-editor/blob/main/app/src/main/assets/textmate/languages.json) 94 | 95 | #### 加载语法和主题 96 | 97 | 在编辑器中使用textmate之前,我们应该将语法和主题文件提前加载到注册表中。 98 | **无论有多少编辑器实例在使用textmate,这些步骤都应该只执行一次。** 99 | 100 | 假设我们要从assets文件夹加载textmate文件。首先,我们需要添加textmate内部文件访问权限。 101 | 102 | ::: code-group 103 | 104 | ```Kotlin Kotlin 105 | FileProviderRegistry.getInstance().addFileProvider( 106 | AssetsFileResolver( 107 | applicationContext.assets // 使用应用上下文 108 | ) 109 | ) 110 | ``` 111 | 112 | ```Java Java 113 | FileProviderRegistry.getInstance().addFileProvider( 114 | new AssetsFileResolver( 115 | getApplicationContext().getAssets() // 使用应用上下文 116 | ) 117 | ) 118 | ``` 119 | 120 | ::: 121 | 122 | 然后,我们需要加载主题。下面的代码演示如何将单个主题加载到编辑器中。 123 | 124 | ::: code-group 125 | 126 | ```Kotlin Kotlin 127 | val themeRegistry = ThemeRegistry.getInstance() 128 | val name = "quietlight" // 主题名称 129 | val themeAssetsPath = "textmate/$name.json" 130 | themeRegistry.loadTheme( 131 | ThemeModel( 132 | IThemeSource.fromInputStream( 133 | FileProviderRegistry.getInstance().tryGetInputStream(themeAssetsPath), themeAssetsPath, null 134 | ), 135 | name 136 | ).apply { 137 | // 如果主题是适用于暗色模式的,请额外添加以下内容 138 | // isDark = true 139 | } 140 | ) 141 | ``` 142 | 143 | ```Java Java 144 | var themeRegistry = ThemeRegistry.getInstance(); 145 | var name = "quietlight"; // 主题名称 146 | var themeAssetsPath = "textmate/" + name + ".json"; 147 | var model = new ThemeModel( 148 | IThemeSource.fromInputStream( 149 | FileProviderRegistry.getInstance().tryGetInputStream(themeAssetsPath), themeAssetsPath, null 150 | ), 151 | name 152 | ); 153 | // 如果主题是适用于暗色模式的,请额外添加以下内容 154 | // model.setDark(true); 155 | themeRegistry.loadTheme(model); 156 | ``` 157 | 158 | ::: 159 | 160 | 接下来,为textmate选择并启用一个主题。textmate将会使用其注册表来管理全局配色方案。 161 | 162 | ::: code-group 163 | 164 | ```Kotlin Kotlin 165 | ThemeRegistry.getInstance().setTheme("您的主题名称") 166 | ``` 167 | 168 | ```Java Java 169 | ThemeRegistry.getInstance().setTheme("您的主题名称"); 170 | ``` 171 | 172 | ::: 173 | 174 | 最后,我们加载语言的语法和配置。 175 | 176 | ::: code-group 177 | 178 | ```Kotlin Kotlin 179 | GrammarRegistry.getInstance().loadGrammars("textmate/languages.json") 180 | ``` 181 | 182 | ```Java Java 183 | GrammarRegistry.getInstance().loadGrammars("textmate/languages.json"); 184 | ``` 185 | 186 | ::: 187 | 188 | ::: details 通过Kotlin DSL语法加载 189 | 190 | 您可以使用Kotlin DSL将Language加载到语法注册表中,而不需要`languages.json`。 191 | 192 | 示例: 193 | 194 | ```Kotlin 195 | GrammarRegistry.getInstance().loadGrammars( 196 | languages { 197 | language("java") { 198 | grammar = "textmate/java/syntaxes/java.tmLanguage.json" 199 | defaultScopeName() 200 | languageConfiguration = "textmate/java/language-configuration.json" 201 | } 202 | language("kotlin") { 203 | grammar = "textmate/kotlin/syntaxes/Kotlin.tmLanguage" 204 | defaultScopeName() 205 | languageConfiguration = "textmate/kotlin/language-configuration.json" 206 | } 207 | language("python") { 208 | grammar = "textmate/python/syntaxes/python.tmLanguage.json" 209 | defaultScopeName() 210 | languageConfiguration = "textmate/python/language-configuration.json" 211 | } 212 | } 213 | ) 214 | ``` 215 | 216 | `defaultScopeName()`会将`scopeName`设置为`source.${languageName}`。 217 | 218 | ::: 219 | 220 | #### Optional Step 221 | 222 | TextMate 默认情况下使用 Joni 作为正则表达式库。Joni 是由纯 Java 实现的,因此在正则表达式匹配过程中,将会生成大量的对象,给虚拟机带来 GC 压力。 223 | 224 | 为此,我们在 `0.24.0` 版本中引入了原生的 [oniguruma](https://github.com/kkos/oniguruma) 实现,您可以引入 `oniguruma-native` 模块以启用它。这能够加速 TextMate 的高亮速度并减少内存分配。 225 | 226 | oniguruma 也是 VSCode 使用的正则表达式库,因此在引入它之后,您应该能使用更多来自 VSCode 的 TextMate Bundles. 227 | 228 | 我们的[oniguruma 分支](https://github.com/project-sora/oniguruma) 目前支持 Unicode 17.0.0. 229 | 230 | #### 设置编辑器 231 | 232 | 设置编辑器的配色方案。如果`TextMateColorScheme`没被应用到编辑器中,则textmate的语法高亮结果的颜色是透明的。 233 | 234 | ::: code-group 235 | 236 | ```Kotlin Kotlin 237 | editor.colorScheme = TextMateColorScheme.create(ThemeRegistry.getInstance()) 238 | ``` 239 | 240 | ```Java Java 241 | editor.setColorScheme(TextMateColorScheme.create(ThemeRegistry.getInstance())); 242 | ``` 243 | 244 | ::: 245 | 246 | 最后,设置编辑器语言。 247 | 248 | ::: code-group 249 | 250 | ```Kotlin Kotlin 251 | val languageScopeName = "source.java" // 您目标语言的作用域名称 252 | val language = TextMateLanguage.create( 253 | languageScopeName, true /* true表示启用自动补全 */ 254 | ) 255 | editor.setEditorLanguage(language) 256 | ``` 257 | 258 | ```Java Java 259 | var languageScopeName = "source.java"; // 您目标语言的作用域名称 260 | var language = TextMateLanguage.create( 261 | languageScopeName, true /* true表示启用自动补全 */ 262 | ); 263 | editor.setEditorLanguage(language); 264 | ``` 265 | 266 | ::: 267 | 268 | 恭喜!您已经完成了所有设置。尽情享受吧! 269 | 270 | ### language-java 271 | 272 | 为Java语言提供基于token的高亮显示、关键字自动补全和代码块标记的支持。它还具有一些用于测试编辑器的实验性功能。 273 | 274 | 虽然它的功能仍然很简单,但它的速度要比其他复杂的语言分析快得多。 275 | 276 | 若要创建并使用它,请参考下面的代码: 277 | 278 | ::: code-group 279 | 280 | ```Kotlin Kotlin 281 | editor.editorLanguage = JavaLanguage() 282 | ``` 283 | 284 | ```Java Java 285 | editor.setEditorLanguage(new JavaLanguage()); 286 | ``` 287 | 288 | ::: 289 | 290 | ### language-treesitter 291 | 292 | TreeSitter由[Atom](https://github.com/atom/atom)和现在[Zed](https://github.com/zed-industries/zed)的作者们开发。 293 | TreeSitter是一个解析器生成器工具和一个增量解析库。 294 | 295 | 使用TreeSitter,我们可以为源文件构建抽象语法树,并在编辑源文件时高效地更新该语法树并使用语法树进行准确的语法高亮显示。 296 | 297 | 我们使用[android-tree-sitter](https://github.com/AndroidIDEOfficial/android-tree-sitter)调用tree-sitter的API。 298 | 299 | 在继续往下阅读前,我们强烈建议您先了解一下编辑器框架中的[TextStyle](https://github.com/Rosemoe/sora-editor/blob/main/editor/src/main/java/io/github/rosemoe/sora/lang/styling/TextStyle.java) 300 | 301 | #### 准备语言 302 | 303 | 您可以先在[android-tree-sitter](https://github.com/AndroidIDEOfficial/android-tree-sitter) 304 | 中查找是否已存在您需要的语言实现。如果没有您需要的语言实现,则您必须自己构建一个适用于Android的语言实现。 305 | 306 | 此外,还需要四个`scm`文件来查询语法树: 307 | 308 | * 309 | 1. 高亮显示 310 | 311 | 对于适用于绝大多数语言的`highlights.scm`都可以在TreeSitter语言存储库中找到。 312 | 例如[这个](https://github.com/tree-sitter/tree-sitter-java/tree/master/queries)适用于Java语言。 313 | 314 | * 315 | 2. 代码块(可选) 316 | 317 | 这个仅适用于sora-editor。 318 | 请参考[这个](https://github.com/Rosemoe/sora-editor/blob/main/app/src/main/assets/tree-sitter-queries/java/blocks.scm)示例 319 | 320 | * 321 | 3. 符号对高亮(可选) 322 | 323 | 这个仅适用于sora-editor。 324 | 请参考[这个](https://github.com/Rosemoe/sora-editor/blob/main/app/src/main/assets/tree-sitter-queries/java/brackets.scm) 325 | 示例 326 | 327 | * 328 | 4. 局部变量(可选) 329 | 330 | 对于适用于大多数语言局部变量的`locals.scm` 331 | 可以在[nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter/tree/master/queries)存储库中找到。 332 | 333 | 相关链接: 334 | 335 | * [TreeSitter组织](https://github.com/tree-sitter) 336 | * [TreeSitter文档](https://tree-sitter.github.io/tree-sitter/) 337 | * [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) 338 | * [Zed Languages](https://github.com/zed-industries/zed/tree/main/crates/zed/src/languages) 339 | 340 | #### 创建语言详细说明 341 | 342 | 首先,`TsLanguageSpec`应该由tree-sitter语言实例和`scm`源文本创建。您可能需要为您的`locals.scm`添加一个自定义的[`LocalsCaptureSpec`](https://github.com/Rosemoe/sora-editor/blob/main/language-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/LocalsCaptureSpec.kt)。 343 | 344 | ```Kotlin 345 | val spec = TsLanguageSpec( 346 | // 您的tree-sitter语言实例 347 | language = TSLanguageJava.getInstance(), 348 | // scm原文本 349 | highlightScmSource = assets.open("tree-sitter-queries/java/highlights.scm") 350 | .reader().readText(), 351 | codeBlocksScmSource = assets.open("tree-sitter-queries/java/blocks.scm") 352 | .reader().readText(), 353 | bracketsScmSource = assets.open("tree-sitter-queries/java/brackets.scm") 354 | .reader().readText(), 355 | localsScmSource = assets.open("tree-sitter-queries/java/locals.scm") 356 | .reader().readText(), 357 | localsCaptureSpec = object : LocalsCaptureSpec() { 358 | // 覆盖和更改任何语言详细说明的方法 359 | } 360 | ) 361 | ``` 362 | 363 | 有时,您的`scm`文件使用外部谓词方法(客户端谓词)来更好地查询语法树。在这种情况下,请将谓词实现添加到`predicates`参数中。 364 | 365 | #### 制作Language和主题 366 | 367 | 使用您的`TsLanguageSpec`和主题构建器DSL语法创建一个`TsLanguage` 368 | 369 | ```Kotlin 370 | // 在Kotlin中轻松制作文本样式的扩展功能 371 | import io.github.rosemoe.sora.lang.styling.textStyle 372 | 373 | // ... 374 | val language = TsLanguage(languageSpec, false /* useTab */) { 375 | // 主题构建器DSL 376 | // 将文本样式应用于捕获的语法节点 377 | 378 | // 将样式应用于单一类型的节点 379 | textStyle(KEYWORD, bold = true) applyTo "keyword" 380 | // 应用于多个节点 381 | textStyle(LITERAL) applyTo arrayOf("constant.builtin", "string", "number") 382 | } 383 | ``` 384 | 385 | #### 应用Language 386 | 387 | 现在,Language实例可以应用于编辑器。 388 | 389 | ```Kotlin 390 | editor.setEditorLanguage(language) 391 | ``` 392 | 393 | 请注意,`TsLanguageSpec`对象不可重复使用,因为`TsLanguage`被销毁时它也会被关闭。 -------------------------------------------------------------------------------- /docs/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # Getting Started 5 | ## Requirements 6 | Before including [sora-editor](https://github.com/Rosemoe/sora-editor) library into your project, please ensure your environment and build configuration satisfy the requirements below: 7 | * Running Gradle on JDK 17 or above 8 | * The minimum Android SDK version of your module is at least Android L (API 21) 9 | * If you are to use [Language Server Protocol](https://microsoft.github.io/language-server-protocol/), the requirement will be at least Android O (API 26) 10 | * Project Java source compatibility and target compatibility is `JavaVersion.VERSION_17` 11 | ::: details Set Java Source and Target Compatibilities 12 | 13 | ::: code-group 14 | 15 | ```Kotlin{3-4,8-10} [Kotlin DSL] 16 | android { 17 | compileOptions { 18 | sourceCompatibility = JavaVersion.VERSION_17 19 | targetCompatibility = JavaVersion.VERSION_17 20 | } 21 | } 22 | // If Kotlin used in your app 23 | // kotlin { 24 | // jvmToolchain(17) 25 | // } 26 | ``` 27 | 28 | ```Groovy{3-4} [Groovy DSL] 29 | android { 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_17 32 | targetCompatibility JavaVersion.VERSION_17 33 | } 34 | } 35 | ``` 36 | 37 | ::: 38 | 39 | 40 | ::: details For Non-Gradle Build Systems 41 | 42 | The editor uses resources and is distributed in AAR files. Your build system must support processing AAR files. 43 | 44 | If you are not using Gradle as your build system, we won't provide information related to your build issues. 45 | 46 | ::: 47 | ## Add Dependencies 48 | 49 | Newest Version: [![Maven Central](https://img.shields.io/maven-central/v/io.github.rosemoe/editor.svg?label=Maven%20Central)]((https://search.maven.org/search?q=io.github.rosemoe%20editor)) 50 | 51 | Add sora-editor library to your app's dependencies: 52 | 53 | ::: code-group 54 | 55 | ```Kotlin{2-3} [Kotlin DSL] 56 | dependencies { 57 | implementation(platform("io.github.rosemoe:editor-bom:")) 58 | implementation("io.github.rosemoe:") 59 | } 60 | ``` 61 | 62 | ```Groovy{2-3} [Groovy DSL] 63 | dependencies { 64 | implementation(platform("io.github.rosemoe:editor-bom:")) 65 | implementation 'io.github.rosemoe:' 66 | } 67 | ``` 68 | 69 | ::: 70 | 71 | Replace the placeholder `` and `` with correct version name and module name. You may add multiple modules to your project. 72 | 73 | Here's an example for those who want to use TextMate grammars for syntax-highlighting in editor: 74 | 75 | ::: code-group 76 | 77 | ```Kotlin{2-4} [Kotlin DSL] 78 | dependencies { 79 | implementation(platform("io.github.rosemoe:editor-bom:0.24.1")) 80 | implementation("io.github.rosemoe:editor") 81 | implementation("io.github.rosemoe:language-textmate") 82 | } 83 | ``` 84 | 85 | ```Groovy{2-4} [Groovy DSL] 86 | dependencies { 87 | implementation(platform("io.github.rosemoe:editor-bom:0.24.1")) 88 | implementation 'io.github.rosemoe:editor' 89 | implementation 'io.github.rosemoe:language-textmate' 90 | } 91 | ``` 92 | 93 | ```Kotlin{2-4} [Kotlin DSL without bom] 94 | dependencies { 95 | val editorVersion = "0.24.1" 96 | implementation("io.github.rosemoe:editor:$editorVersion") 97 | implementation("io.github.rosemoe:language-textmate:$editorVersion") 98 | } 99 | ``` 100 | 101 | ```Groovy{2-4} [Groovy DSL without bom] 102 | dependencies { 103 | def editorVersion = '0.24.1' 104 | implementation 'io.github.rosemoe:editor:$editorVersion' 105 | implementation 'io.github.rosemoe:language-textmate:$editorVersion' 106 | } 107 | ``` 108 | 109 | ::: 110 | 111 | ::: tip NOTE 112 | 113 | You can find the newest version name from the badge above, or turn to our GitHub [Releases](https://github.com/Rosemoe/sora-editor/releases) page for full version list. 114 | 115 | Currently, available modules names are: `editor`, `editor-lsp`, `language-java`, `language-textmate` and `language-treesitter`. 116 | Check the table below to get more information about the modules. 117 | 118 | ::: 119 | 120 | ### 🛠️Available modules 121 | 122 | | Module | Summary | 123 | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 124 | | editor | Widget library containing all basic things of the framework | 125 | | editor-lsp | A convenient library for creating languages by [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) (aka LSP) | 126 | | language-java | A simple implementation for Java lexer-based highlighting and identifier auto-completion | 127 | | language-textmate | An advanced highlighter for the editor. It can be used to load TextMate language bundles and themes. The internal implementation of TextMate is from [tm4e](https://github.com/eclipse/tm4e) | 128 | | language-treesitter | Offer [tree-sitter](https://tree-sitter.github.io/tree-sitter/) support for editor. This can be used to parse the code to an AST fast and incrementally, which is helpful for accurate highlighting and providing completions. Note that this module only provides incremental parsing and highlighting. Thanks to Java bindings [android-tree-sitter](https://github.com/AndroidIDEOfficial/android-tree-sitter/) | 129 | 130 | | oniguruma-native | Regexp library for language-textmate. Not used by default. | 131 | 132 | ### 🚧Snapshot Builds 133 | 134 | Generally, it is recommended to use [released versions](https://github.com/Rosemoe/sora-editor/releases). But sometimes you may still want to use nightly builds for latest bug fixes and enhancements. 135 | 136 | ::: details How to Use Snapshot Builds 137 | 138 | Snapshot versions are automatically published on repository push. You may combine current released version name 139 | and `-SNAPSHOT` to make a snapshot version name. 140 | 141 | For example, if the latest released version name is `0.24.1`, you may use version name `0.24.1-SNAPSHOT` to import the snapshot version to your project. 142 | 143 | Note that adding extra maven repository is required: 144 | ```Kotlin{3} 145 | repositories { 146 | // ... 147 | maven("https://central.sonatype.com/repository/maven-snapshots") 148 | } 149 | ``` 150 | 151 | Due to Central Portal limitations, the snapshot version is only kept for 90 days. 152 | 153 | ::: 154 | 155 | ## Configure Desugaring for TextMate 156 | 157 | If you use `language-textmate` module in your project, and want to run the application on devices under Android 13 (API 33), you **must** enable [Core Library Desugaring](https://developer.android.google.cn/studio/write/java8-support#library-desugaring) to avoid compatibility issues. Otherwise, you can go on to next section. 158 | 159 | To enable the desugaring, follow the instructions below to setup your **application module**. Note that the following instructions are for AGP 7.4.0 or above. 160 | 161 | * Add Desugaring Dependency 162 | ::: code-group 163 | 164 | ```Kotlin [Kotlin DSL] 165 | dependencies { 166 | coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") // [!code highlight] 167 | } 168 | ``` 169 | 170 | ```Groovy [Groovy DSL] 171 | dependencies { 172 | coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5' // [!code highlight] 173 | } 174 | ``` 175 | 176 | ::: 177 | 178 | * Add Compile Option 179 | ::: code-group 180 | 181 | ```Kotlin [Kotlin DSL] 182 | android { 183 | compileOptions { 184 | isCoreLibraryDesugaringEnabled = true // [!code highlight] 185 | } 186 | } 187 | ``` 188 | 189 | ```Groovy [Groovy DSL] 190 | android { 191 | compileOptions { 192 | coreLibraryDesugaringEnabled true // [!code highlight] 193 | } 194 | } 195 | ``` 196 | 197 | ::: 198 | 199 | ::: warning BE CAUTIOUS 200 | When desugaring is enabled, you should build the production APK in Android Studio by: 201 | * Build from menu `Build` | `Build Bundle(s) / APK(s)` | `Build APK(s)` 202 | * Or, run Gradle task `assemble`. For example, execute `assembleDebug` for your `debug` variant. 203 | 204 | Android Studio tries to speed up the desugaring process when you run the application on a specific device from clicking the `Run` button (or shortcuts `Shift+F10`). It will generate a device API specific APK, and as a result the APK may not work properly on other devices. 205 | 206 | Alternatively, you can disable this feature in Android Studio by disabling `Experimental > Optimize build for target device API level only` in preferences to avoid this issue. 207 | ::: 208 | 209 | ## Create the Widget 210 | 211 | Please ensure you have included `editor` module in your project, and then sync your project with Gradle files successfully. 212 | 213 | The main widget class is `io.github.rosemoe.sora.widget.CodeEditor`. You can create the code editor either by XML or Java/Kotlin code(recommended). Only limited editor attributes can be set in XML. 214 | ### Use in XML 215 | Declare editor in your layout XML files: 216 | ```XML 217 | 223 | ``` 224 | It's not necessary to set `text` or `textSize` in XML declaration. 225 | 226 | Refer to [XML Attributes](/reference/xml-attributes) for more information about its usage in XML. 227 | ::: tip NOTE 228 | It is not recommended to use `wrap_content` for editor width or height. In that case, when the text is editted, the editor has to request re-layout which probably causes lags. 229 | ::: 230 | ### Use in Java/Kotlin code 231 | Just create a editor and add it to any view group. Supposing we are in any `Activity` context, and `vg` is a `ViewGroup` instance. 232 | ::: code-group 233 | ```Kotlin [Kotlin] 234 | val editor = CodeEditor(this) 235 | editor.setText("Hello, world!") // Set text 236 | editor.typefaceText = Typeface.MONOSPACE // Use Monospace Typeface 237 | editor.nonPrintablePaintingFlags = 238 | CodeEditor.FLAG_DRAW_WHITESPACE_LEADING or CodeEditor.FLAG_DRAW_LINE_SEPARATOR or CodeEditor.FLAG_DRAW_WHITESPACE_IN_SELECTION // Show Non-Printable Characters 239 | vg.add(editor, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)) 240 | ``` 241 | ```Java [Java] 242 | var editor = new CodeEditor(this); 243 | editor.setText("Hello, world!"); // Set Text 244 | editor.setTypefaceText(Typeface.MONOSPACE); // Use Monospace Typeface 245 | editor.setNonPrintablePaintingFlags( 246 | CodeEditor.FLAG_DRAW_WHITESPACE_LEADING | CodeEditor.FLAG_DRAW_LINE_SEPARATOR | CodeEditor.FLAG_DRAW_WHITESPACE_IN_SELECTION); // Show Non-Printable Characters 247 | vg.add(editor, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); 248 | ``` 249 | ::: 250 | Please view methods of `CodeEditor` and fields of `DirectAccessProps` for more attributes you can configure. 251 | ::: warning BE CAUTIOUS 252 | Not all fields of `DirectAccessProps` can take effect without invalidation. Call `invalidate()` on editor after changing those fields marked with `@InvalidateRequired`. 253 | 254 | Methods and fields that marked with `@UnsupportedUserUsage` should not be used. They are visible for internal access. 255 | ::: 256 | ## Release the Widget 257 | When a `CodeEditor` instance is no longer used, its `release()` method **must** be invoked to release resources and any background thread serving for the editor. 258 | After releasing the editor, you should not use the editor, to avoid errors. 259 | 260 | ::: code-group 261 | 262 | ```Kotlin Kotlin 263 | override fun onDestroy() { 264 | super.onDestroy() 265 | editor?.release() 266 | } 267 | ``` 268 | 269 | ```Java Java 270 | @Override 271 | protected void onDestroy() { 272 | super.onDestroy(); 273 | if (editor != null) { 274 | editor.release(); 275 | } 276 | } 277 | ``` 278 | 279 | ::: 280 | ## Continue 281 | Go to [Language](./using-language.md) and [Color Scheme](./using-color-scheme.md) to equip the editor with programming language support and your custom color scheme. -------------------------------------------------------------------------------- /docs/guide/using-language.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | # Language 5 | Language is the interface in Sora Editor to provide language-specific functionality, including syntax analysis, auto-completion and auto-indent. 6 | 7 | Single `Language` instance should serve for only one editor. And it is automatically destroyed when the editor is released or a new `Language` instance is set. 8 | 9 | You can use `CodeEditor#setEditorLanguage` to apply a new `Language` to it. By default, the editor uses built-in `EmptyLanguage` and no analysis is performed. Thus, syntax-highlight and other language features are unavailable. 10 | 11 | We provide some universal language implementation for you to setup the analysis and syntax-highlight for a programming language. Note that `language-java` module is only for simple token-based Java syntax-highlight. 12 | ## Use Language Modules 13 | Before using the language module, make sure you have imported it into your project. 14 | ### language-textmate 15 | This module uses [TextMate](https://github.com/textmate/textmate) grammars to help tokenize text and highlight for various programming languages. TextMate is also used in [Visual Studio Code](https://github.com/microsoft/vscode) and [Eclipse](https://github.com/eclipse/tm4e) for syntax-highlight. Most library integrators will in favour of using this module instead of writing `Language` implementation themselves. 16 | 17 | Follow the steps below to use TextMate for your editor. 18 | #### Find Language Syntax and Config 19 | TextMate supports various languages, and syntax-highlight rules are defined by `*.tmLanguage` PLIST files or `*.tmLanguage.json` JSON files. You need these TextMate rule files (aka `syntaxes`) and optionally language configuration files (`*.language-configuration.json`) for your target language. 20 | 21 | You can find those files in: 22 | * [TM4E Language Packs](https://github.com/eclipse/tm4e/tree/25e7fbe39c02644ca5d541d20a2c601791af7b8d/org.eclipse.tm4e.language_pack/syntaxes) 23 | * [VSCode Extensions](https://github.com/microsoft/vscode/tree/4f2ff19ecacffa0aa4874db4d63ed4e899d98431/extensions) 24 | 25 | ::: tip NOTE 26 | 27 | Some TextMate syntaxes are not fully supported by current TextMate engine. Because the regexp library [Joni](https://github.com/jruby/joni) does not fully support those regular expressions used in grammar files. 28 | 29 | These regexps will fallback to `^$` to avoid errors during highlight analysis. 30 | 31 | ::: 32 | #### Find Themes 33 | TextMate must be used together with TextMate themes. You also need to find theme JSON files from [VSCode Extensions](https://github.com/microsoft/vscode/tree/4f2ff19ecacffa0aa4874db4d63ed4e899d98431/extensions). 34 | There are some folders named in `theme-*` pattern. Those folders are for VSCode built-in TextMate themes. 35 | #### Prepare Language Registry 36 | Multiple languages can be loaded by TextMate. We should prepare `languages.json` for later loading. For exmaple, your assets directory: 37 | ```Text 38 | . 39 | ├─ textmate 40 | │ ├─ java 41 | │ │ ├─ syntaxes 42 | │ │ │ └─ java.tmLanguage.json 43 | │ │ └─ language-configuration.json 44 | │ └─ kotlin 45 | │ ├─ syntaxes 46 | │ │ └─ Kotlin.tmLanguage 47 | │ └─ language-configuration.json 48 | └─ language.json 49 | ``` 50 | Your `language.json`: 51 | ```JSON 52 | { 53 | "languages": [ 54 | { 55 | "grammar": "textmate/java/syntaxes/java.tmLanguage.json", 56 | "name": "java", 57 | "scopeName": "source.java", 58 | "languageConfiguration": "textmate/java/language-configuration.json" 59 | }, 60 | { 61 | "grammar": "textmate/kotlin/syntaxes/Kotlin.tmLanguage", 62 | "name": "kotlin", 63 | "scopeName": "source.kotlin", 64 | "languageConfiguration": "textmate/kotlin/language-configuration.json" 65 | } 66 | ] 67 | } 68 | ``` 69 | `name` is custom and `scopeName` is the root scope of the syntax file. 70 | 71 | For language (like HTML and Markdown) with embedded languages, refer to HTML sample in [Demo App](https://github.com/Rosemoe/sora-editor/blob/main/app/src/main/assets/textmate/languages.json) 72 | #### Load Syntaxes and Themes 73 | Before using TextMate languages in editor, we should load the syntax and theme files into registry. **These steps are performed only once, no matter how many editors are to use TextMate.** 74 | 75 | Supposing we are to load textmate files from our APK assets. First, we need to add `FileResolver` for TextMate internal file access. 76 | ::: code-group 77 | 78 | ```Kotlin Kotlin 79 | FileProviderRegistry.getInstance().addFileProvider( 80 | AssetsFileResolver( 81 | applicationContext.assets // use application context 82 | ) 83 | ) 84 | ``` 85 | 86 | ```Java Java 87 | FileProviderRegistry.getInstance().addFileProvider( 88 | new AssetsFileResolver( 89 | getApplicationContext().getAssets() // use application context 90 | ) 91 | ) 92 | ``` 93 | 94 | ::: 95 | Then, the themes should be loaded. The code below shows how to load a single theme into the editor. 96 | ::: code-group 97 | 98 | ```Kotlin Kotlin 99 | val themeRegistry = ThemeRegistry.getInstance() 100 | val name = "quietlight" // name of theme 101 | val themeAssetsPath = "textmate/$name.json" 102 | themeRegistry.loadTheme( 103 | ThemeModel( 104 | IThemeSource.fromInputStream( 105 | FileProviderRegistry.getInstance().tryGetInputStream(themeAssetsPath), themeAssetsPath, null 106 | ), 107 | name 108 | ).apply { 109 | // If the theme is dark 110 | // isDark = true 111 | } 112 | ) 113 | ``` 114 | 115 | ```Java Java 116 | var themeRegistry = ThemeRegistry.getInstance(); 117 | var name = "quietlight"; // name of theme 118 | var themeAssetsPath = "textmate/" + name + ".json"; 119 | var model = new ThemeModel( 120 | IThemeSource.fromInputStream( 121 | FileProviderRegistry.getInstance().tryGetInputStream(themeAssetsPath), themeAssetsPath, null 122 | ), 123 | name 124 | ); 125 | // If the theme is dark 126 | // model.setDark(true); 127 | themeRegistry.loadTheme(model); 128 | ``` 129 | 130 | ::: 131 | Next, select an active theme for TextMate. TextMate uses its registry to manage global color scheme. 132 | ::: code-group 133 | 134 | ```Kotlin Kotlin 135 | ThemeRegistry.getInstance().setTheme("your-theme-name") 136 | ``` 137 | 138 | ```Java Java 139 | ThemeRegistry.getInstance().setTheme("your-theme-name"); 140 | ``` 141 | 142 | ::: 143 | Finally, we load the language syntaxes and configurations. 144 | 145 | ::: code-group 146 | 147 | ```Kotlin Kotlin 148 | GrammarRegistry.getInstance().loadGrammars("textmate/languages.json") 149 | ``` 150 | 151 | ```Java Java 152 | GrammarRegistry.getInstance().loadGrammars("textmate/languages.json"); 153 | ``` 154 | 155 | ::: 156 | 157 | ::: details Load by Kotlin DSL 158 | 159 | You can load languages into grammar registry without `languages.json`, by Kotlin DSL. 160 | 161 | For example: 162 | 163 | ```Kotlin 164 | GrammarRegistry.getInstance().loadGrammars( 165 | languages { 166 | language("java") { 167 | grammar = "textmate/java/syntaxes/java.tmLanguage.json" 168 | defaultScopeName() 169 | languageConfiguration = "textmate/java/language-configuration.json" 170 | } 171 | language("kotlin") { 172 | grammar = "textmate/kotlin/syntaxes/Kotlin.tmLanguage" 173 | defaultScopeName() 174 | languageConfiguration = "textmate/kotlin/language-configuration.json" 175 | } 176 | language("python") { 177 | grammar = "textmate/python/syntaxes/python.tmLanguage.json" 178 | defaultScopeName() 179 | languageConfiguration = "textmate/python/language-configuration.json" 180 | } 181 | } 182 | ) 183 | ``` 184 | 185 | `defaultScopeName()` sets `scopeName` to `source.${languageName}`. 186 | 187 | ::: 188 | 189 | #### Optional Step 190 | 191 | TextMate uses Joni by default. Joni is a regexp library implemented in pure Java so during regexp matching, a bunch of objects are allocated and this 192 | add pressure for ART GC. 193 | 194 | We introduced native [oniguruma](https://github.com/kkos/oniguruma) implementation to match regexps since version `0.24.0`, you may include `oniguruma-native` module to enable it. This brings faster highlighting speed and less JVM heap allocations. 195 | 196 | Also, oniguruma is the regexp library used by VSCode, so with the library included you may use more TextMate bundles from VSCode. 197 | 198 | Our [forked oniguruma](https://github.com/project-sora/oniguruma) currently supports up to Unicode 17.0.0. 199 | 200 | #### Setup Editor 201 | Set color scheme for the editor. If `TextMateColorScheme` is not applied to the editor, the colors of syntax-highlight result from TextMate will be transparent. 202 | ::: code-group 203 | 204 | ```Kotlin Kotlin 205 | editor.colorScheme = TextMateColorScheme.create(ThemeRegistry.getInstance()) 206 | ``` 207 | 208 | ```Java Java 209 | editor.setColorScheme(TextMateColorScheme.create(ThemeRegistry.getInstance())); 210 | ``` 211 | 212 | ::: 213 | Set editor language. 214 | ::: code-group 215 | 216 | ```Kotlin Kotlin 217 | val languageScopeName = "source.java" // The scope name of target language 218 | val language = TextMateLanguage.create( 219 | languageScopeName, true /* true for enabling auto-completion */ 220 | ) 221 | editor.setEditorLanguage(language) 222 | ``` 223 | 224 | ```Java Java 225 | var languageScopeName = "source.java"; // The scope name of target language 226 | var language = TextMateLanguage.create( 227 | languageScopeName, true /* true for enabling auto-completion */ 228 | ); 229 | editor.setEditorLanguage(language); 230 | ``` 231 | 232 | ::: 233 | Congratulations! You've done all the setup. Enjoy! 234 | ### language-java 235 | The Java language support provides token-based highlight, identifier auto-completion and code block markers. It also has some experimental features for testing editor. 236 | 237 | Though its functionality remains to be simple, its speed is fairly fast than other complex language analysis. 238 | 239 | To create and apply the language, see code below: 240 | ::: code-group 241 | 242 | ```Kotlin Kotlin 243 | editor.editorLanguage = JavaLanguage() 244 | ``` 245 | 246 | ```Java Java 247 | editor.setEditorLanguage(new JavaLanguage()); 248 | ``` 249 | 250 | ::: 251 | ### language-treesitter 252 | TreeSitter is developed by the creators of [Atom](https://github.com/atom/atom) and now [Zed](https://github.com/zed-industries/zed) and used in the two code editors. TreeSitter is a parser generator tool and an incremental parsing library. 253 | 254 | With TreeSitter, we can build a concrete syntax tree for a source file and efficiently update the syntax tree as the source file is edited. And use the syntax tree for accurate syntax-highlight. 255 | 256 | We use Java binding [android-tree-sitter](https://github.com/AndroidIDEOfficial/android-tree-sitter) to invoke tree-sitter APIs. 257 | 258 | Before reading ahead, we strongly recommend you to check out [TextStyle](https://github.com/Rosemoe/sora-editor/blob/main/editor/src/main/java/io/github/rosemoe/sora/lang/styling/TextStyle.java) in editor framework first. 259 | 260 | #### Prepare Language 261 | 262 | You can find existing language implementation 263 | from [android-tree-sitter](https://github.com/AndroidIDEOfficial/android-tree-sitter). If the language you want is 264 | missing, you have to build the language for Android on your own. 265 | 266 | Besides, Four `scm` files for querying the syntax tree are required. 267 | * 1. For highlight 268 | `highlights.scm` for most languages can be found in TreeSitter language repositories. For exmaple, the one for Java is [here](https://github.com/tree-sitter/tree-sitter-java/tree/master/queries) 269 | * 2. For code blocks (optional) 270 | This is sora-editor specific queries. Refer to [here](https://github.com/Rosemoe/sora-editor/blob/main/app/src/main/assets/tree-sitter-queries/java/blocks.scm) for instructions and sample. 271 | * 3. For brackets (optional) 272 | This is sora-editor specific queries. Refer to [here](https://github.com/Rosemoe/sora-editor/blob/main/app/src/main/assets/tree-sitter-queries/java/brackets.scm) for instructions and sample. 273 | * 4. For local variables (optional) 274 | `locals.scm` for most languages can be found in [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter/tree/master/queries) repository. 275 | 276 | Useful Links: 277 | * [TreeSitter Organization](https://github.com/tree-sitter) 278 | * [TreeSitter Documentation](https://tree-sitter.github.io/tree-sitter/) 279 | * [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) 280 | * [Zed Languages](https://github.com/zed-industries/zed/tree/main/crates/zed/src/languages) 281 | #### Create Language Spec 282 | First, `TsLanguageSpec` should be created with tree-sitter language instance and `scm` source texts. You may also need to add a custom [`LocalsCaptureSpec`](https://github.com/Rosemoe/sora-editor/blob/main/language-treesitter/src/main/java/io/github/rosemoe/sora/editor/ts/LocalsCaptureSpec.kt) for your `locals.scm`. 283 | 284 | ```Kotlin 285 | val spec = TsLanguageSpec( 286 | // Your tree-sitter language instance 287 | language = TSLanguageJava.getInstance(), 288 | // scm source texts 289 | highlightScmSource = assets.open("tree-sitter-queries/java/highlights.scm") 290 | .reader().readText(), 291 | codeBlocksScmSource = assets.open("tree-sitter-queries/java/blocks.scm") 292 | .reader().readText(), 293 | bracketsScmSource = assets.open("tree-sitter-queries/java/brackets.scm") 294 | .reader().readText(), 295 | localsScmSource = assets.open("tree-sitter-queries/java/locals.scm") 296 | .reader().readText(), 297 | localsCaptureSpec = object : LocalsCaptureSpec() { 298 | // Override any method to change the specification 299 | } 300 | ) 301 | ``` 302 | Sometimes, your `scm` file uses external predicate methods (client predicates) to better querying the syntax tree. In this case, add your predicate implementations to the `predicates` argument. 303 | #### Make Language and Theme 304 | Create a `TsLanguage` with your `TsLanguageSpec` and theme builder DSL. 305 | ```Kotlin 306 | // Extension Function for easily make text styles in Kotlin 307 | import io.github.rosemoe.sora.lang.styling.textStyle 308 | 309 | // ... 310 | val language = TsLanguage(languageSpec, false /* useTab */) { 311 | // Theme Builder DSL 312 | // Apply text style to captured syntax nodes 313 | 314 | // Apply style to single type of node 315 | textStyle(KEYWORD, bold = true) applyTo "keyword" 316 | // Apply to multiple 317 | textStyle(LITERAL) applyTo arrayOf("constant.builtin", "string", "number") 318 | } 319 | ``` 320 | #### Apply Language 321 | Now the language instance can be applied to the editor. 322 | ```Kotlin 323 | editor.setEditorLanguage(language) 324 | ``` 325 | Note that, the `TsLanguageSpec` object can not be reused, because it is closed when the `TsLanguage` is destroyed. --------------------------------------------------------------------------------