From cbae75281f29dcdcc89fd8d9a25b971527432721 Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Sun, 10 Feb 2019 03:35:20 +0100 Subject: [PATCH 1/3] replaced sample text string resource with raw resource --- .../markusressel/kodeeditor/MainActivity.kt | 8 +- app/src/main/res/raw/sample_text | 186 ++++ app/src/main/res/values/strings.xml | 980 ------------------ 3 files changed, 193 insertions(+), 981 deletions(-) create mode 100644 app/src/main/res/raw/sample_text diff --git a/app/src/main/java/de/markusressel/kodeeditor/MainActivity.kt b/app/src/main/java/de/markusressel/kodeeditor/MainActivity.kt index 0c938b7..8a47892 100644 --- a/app/src/main/java/de/markusressel/kodeeditor/MainActivity.kt +++ b/app/src/main/java/de/markusressel/kodeeditor/MainActivity.kt @@ -2,6 +2,7 @@ package de.markusressel.kodeeditor import android.graphics.Color import android.os.Bundle +import android.support.annotation.RawRes import android.support.v7.app.AppCompatActivity import com.github.kittinunf.fuel.Fuel import de.markusressel.kodeeditor.library.extensions.dpToPx @@ -35,7 +36,8 @@ class MainActivity : AppCompatActivity() { if (error != null || text == null) { // fallback if no network is available - codeEditorLayout.setText(R.string.demo_text) + val sampleText = readResourceFileAsText(R.raw.sample_text) + codeEditorLayout.text = sampleText } else { codeEditorLayout.text = text } @@ -43,4 +45,8 @@ class MainActivity : AppCompatActivity() { } } + private fun readResourceFileAsText(@RawRes resourceId: Int): String { + return resources.openRawResource(resourceId).bufferedReader().readText() + } + } diff --git a/app/src/main/res/raw/sample_text b/app/src/main/res/raw/sample_text new file mode 100644 index 0000000..89d96dc --- /dev/null +++ b/app/src/main/res/raw/sample_text @@ -0,0 +1,186 @@ +# KodeEditor +A simple code editor with syntax highlighting and pinch to zoom + +![Editing](https://thumbs.gfycat.com/TalkativeGrandIchthyosaurs-size_restricted.gif) +![Scroll and zoom](https://thumbs.gfycat.com/BouncyLividBlackbear-size_restricted.gif) +![Minimap](https://thumbs.gfycat.com/VigorousDimFrog-size_restricted.gif) + +# Build Status + +| Master | Dev | +|--------|-----| +| [![Master](https://travis-ci.org/markusressel/KodeEditor.svg?branch=master)](https://travis-ci.org/markusressel/KodeEditor/branches) | [![Master](https://travis-ci.org/markusressel/KutePreferences.svg?branch=dev)](https://travis-ci.org/markusressel/KodeEditor/branches) | +| [![codebeat badge](https://codebeat.co/badges/f7fa8602-1d15-457e-904d-cb585e984952)](https://codebeat.co/projects/github-com-markusressel-kodeeditor-master) | [![codebeat badge](https://codebeat.co/badges/19447977-bc96-4519-90b1-e532139ae1a5)](https://codebeat.co/projects/github-com-markusressel-kodeeditor-dev) | + +# Features +* Pinch-To-Zoom +* Line numbers +* Syntax highlighting + * import languages you need + * or simply create your own highlighter using **regex** or other techniques + * themes +* "Minimap" style document overview +* Written entirely in Kotlin + +# How to use +Have a look at the demo app (`app` module) for a complete sample. + +## Gradle +To use this library just include it in your dependencies using + + repositories { + ... + maven { url "https://jitpack.io" } + } + +in your project build.gradle file and + +``` +dependencies { + ... + + def codeEditorVersion = "v2.1.0" + implementation("com.github.markusressel.KodeEditor:library:${codeEditorVersion}") +} +``` + +in your desired module ```build.gradle``` file. + +## Add to your layout + +To use this editor simply add something similar to this to your desired layout xml file: + +``` + +``` + +## Syntax highlighting + +### Language Autodetection + +Currently there is no auto detection for the language used in a document. +You have to manage the syntax highlighter yourself and call the `setSyntaxHighlighter` method when appropriate. + +### Integrated syntax highlighters + +Have a look at the [KodeHighlighter section about this](https://github.com/markusressel/KodeHighlighter). + +### Writing a custom syntax highlighter + +Have a look at the [KodeHighlighter section about this](https://github.com/markusressel/KodeHighlighter). + +## Styling + +KodeEditor can be styled in multiple ways: + +1. xml attributes on KodeEditor +1. theme attributes in your custom theme +1. methods on the view object itself + +### Theme Attributes + +| Name | Description | Type | Default | +|---------------------------|------------------------------------------|----------|----------------------------------------| +| ke_lineNumbers_textColor | Specifies the text color of line numbers | Color | `android.R.attr.textColorPrimary` | +| ke_lineNumbers_backgroundColor | Specifies the background color of the line numbers view | Color | `android.R.attr.windowBackground` | +| ke_divider_enabled | Specifies if a divider should be drawn between line numbers and the actual code editor content | Boolean | `true` | +| ke_divider_color | Specifies the color of the divider (has no effect if `ke_divider_enabled` is set to `false`) | Color | `android.R.attr.textColorPrimary` | +| ke_editor_backgroundColor | Specifies the background color of the code editor view | Color | `android.R.attr.windowBackground` | +| ke_editor_maxZoom | Specifies the maximum zoom level of the editor | Float | `10` | +| ke_minimap_enabled | Enables the minimap | Boolean | `true` | +| ke_minimap_maxDimension | Specifies the maximum dimension of the minimap for both axis | Dimension | `150dp` | +| ke_minimap_borderColor | Specifies the border color of the minimap | Color | `Color.BLACK` | +| ke_minimap_indicatorColor | Specifies the color of the minimap indicator | Color | `Color.RED` | + +You can either use those attributes directly on the view in your layout like this: + +``` + +``` + +or specify them in your application theme (`styles.xml` in dem app) for to apply a style globally: + +``` + + + + + + +``` + +# Contributing + +GitHub is for social coding: if you want to write code, I encourage contributions through pull requests from forks +of this repository. Create GitHub tickets for bugs and new features and comment on the ones that you are interested in. + +# License + +``` +MIT License + +Copyright (c) 2018 Markus Ressel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ebe81d1..a96ba16 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,983 +1,3 @@ KodeEditor - - - - From f30ea49bf2eda39582086f679cf04269263f803e Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Sun, 10 Feb 2019 04:33:27 +0100 Subject: [PATCH 2/3] added SelectionChangedListener interface added api method to set selection listener updated README --- README.md | 48 +++++++++++++++++++ .../markusressel/kodeeditor/MainActivity.kt | 5 ++ .../kodeeditor/library/view/CodeEditText.kt | 10 ++++ .../kodeeditor/library/view/CodeEditorView.kt | 41 +++++++++++++++- .../kodeeditor/library/view/CodeTextView.kt | 10 ++++ .../library/view/SelectionChangedListener.kt | 17 +++++++ 6 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 library/src/main/java/de/markusressel/kodeeditor/library/view/SelectionChangedListener.kt diff --git a/README.md b/README.md index c6e5ac1..5bd3622 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,54 @@ or specify them in your application theme (`styles.xml` in dem app) for to apply ``` +# APIs + +All styling attributes can also be specified using code. Since `KodeEditorLayout` +is just a wrapper to extend the `CodeEditorView` with line numbers and the minimap to use +some of those methods you need to access the matching property of the `KodeEditorLayout` first. + +## KodeEditorLayout + +| Name | Description | Type | +|------|-------------|------| +| text | Sets the given text in the editor. | String | +| setText(@StringRes) | Sets the given strint resource as the text in the editor. | Int | +| syntaxHighlighter | Gets/Sets the active syntax highlighter. Use `null` to disable highlighting altogether. | SyntaxHighlighter? | +| editable | Gets/Sets if the editor content is editable. | Boolean | + +### Line numbers + +| Name | Description | Type | +|------|-------------|------| +| showDivider | Gets/Sets if the divider between line numbers and code editor is shown. | Boolean | + +### Minimap + +| Name | Description | Type | +|------|-------------|------| +| showMinimap | Gets/Sets if the minimap is shown. | Boolean | +| minimapMaxDimension | Gets/Sets the maximum dimension of the minimap in pixels. | Float | +| minimapBorderWidth | Gets/Sets the minimap border size in in pixels. | Number | +| minimapBorderColor | Gets/Sets the minimap border color. | @ColorInt | +| minimapIndicatorColor | Gets/Sets the minimap indicator color. | @ColorInt | + +## CodeEditorView + +To acces these API methods use the `codeEditorLayout.codeEditorView` property. + +| Name | Description | Type | +|------|-------------|------| +| text | Sets the given text in the editor. | String | +| setText(@StringRes) | Sets the given strint resource as the text in the editor. | Int | +| getLineCount() | Returns the current line count. | Long | +| syntaxHighlighter | Gets/Sets the active syntax highlighter. Use `null` to disable highlighting altogether. | SyntaxHighlighter? | +| editable | Gets/Sets if the editor content is editable. | Boolean | +| hasSelection | True when a range is selected. | Boolean | +| selectionStart | The start index of the current selection. | Int | +| selectionEnd | The end index of the current selection. | Int | +| selectionChangedListener | Gets/Sets the Listener for selection changes. | SelectionChangedListener? | + + # Contributing GitHub is for social coding: if you want to write code, I encourage contributions through pull requests from forks diff --git a/app/src/main/java/de/markusressel/kodeeditor/MainActivity.kt b/app/src/main/java/de/markusressel/kodeeditor/MainActivity.kt index 8a47892..cf2e73b 100644 --- a/app/src/main/java/de/markusressel/kodeeditor/MainActivity.kt +++ b/app/src/main/java/de/markusressel/kodeeditor/MainActivity.kt @@ -6,6 +6,7 @@ import android.support.annotation.RawRes import android.support.v7.app.AppCompatActivity import com.github.kittinunf.fuel.Fuel import de.markusressel.kodeeditor.library.extensions.dpToPx +import de.markusressel.kodeeditor.library.view.SelectionChangedListener import de.markusressel.kodehighlighter.language.markdown.MarkdownSyntaxHighlighter import kotlinx.android.synthetic.main.activity_main.* @@ -26,6 +27,10 @@ class MainActivity : AppCompatActivity() { minimapMaxDimension = 150.dpToPx(context) } + codeEditorLayout.codeEditorView.selectionChangedListener = object : SelectionChangedListener { + override fun onSelectionChanged(start: Int, end: Int, hasSelection: Boolean) {} + } + initEditorText() } diff --git a/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeEditText.kt b/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeEditText.kt index f138a4d..b8a8ca4 100644 --- a/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeEditText.kt +++ b/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeEditText.kt @@ -40,6 +40,11 @@ constructor(context: Context, initSyntaxHighlighter() } + /** + * Listener for selection changes + */ + var selectionChangedListener: SelectionChangedListener? = null + private var highlightingTimeout = 50L to TimeUnit.MILLISECONDS private var highlightingDisposable: Disposable? = null @@ -115,6 +120,11 @@ constructor(context: Context, ?: Log.w(TAG, "No syntax highlighter is set!") } + override fun onSelectionChanged(selStart: Int, selEnd: Int) { + super.onSelectionChanged(selStart, selEnd) + selectionChangedListener?.onSelectionChanged(selStart, selEnd, hasSelection()) + } + companion object { const val TAG = "CodeEditText" } diff --git a/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeEditorView.kt b/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeEditorView.kt index 0d3d9f1..0f2f49d 100644 --- a/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeEditorView.kt +++ b/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeEditorView.kt @@ -2,11 +2,13 @@ package de.markusressel.kodeeditor.library.view import android.content.Context import android.graphics.Color +import android.support.annotation.CallSuper import android.support.annotation.StringRes import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.TextView import com.otaliastudios.zoom.ZoomApi import com.otaliastudios.zoom.ZoomLayout import de.markusressel.kodeeditor.library.R @@ -21,7 +23,7 @@ import de.markusressel.kodehighlighter.core.SyntaxHighlighter */ open class CodeEditorView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) - : ZoomLayout(context, attrs, defStyleAttr) { + : ZoomLayout(context, attrs, defStyleAttr), SelectionChangedListener { /** * The actual text editor content @@ -48,6 +50,11 @@ open class CodeEditorView } } + /** + * Listener for selection changes + */ + var selectionChangedListener: SelectionChangedListener? = null + /** * The current text */ @@ -58,6 +65,27 @@ open class CodeEditorView codeTextView.text = value } + /** The start index of the current selection */ + val selectionStart: Int + get() { + val activeView: TextView = if (editable) codeEditText else codeTextView + return activeView.selectionStart + } + + /** The end index of the current selection */ + val selectionEnd: Int + get() { + val activeView: TextView = if (editable) codeEditText else codeTextView + return activeView.selectionEnd + } + + /** True when a range is selected */ + val hasSelection: Boolean + get() { + val activeView: TextView = if (editable) codeEditText else codeTextView + return activeView.hasSelection() + } + /** * Set the text in the editor * @@ -118,9 +146,11 @@ open class CodeEditorView codeEditText.post { codeEditText.setSelection(0) } + codeEditText.selectionChangedListener = this codeTextView = findViewById(R.id.cev_editor_codeTextView) codeTextView.setViewBackgroundWithoutResettingPadding(null) + codeTextView.selectionChangedListener = this } private var firstInit = true @@ -166,6 +196,15 @@ open class CodeEditorView } } + /** + * Called when the selection changes. + * Override this if you are interested in such events. + */ + @CallSuper + override fun onSelectionChanged(start: Int, end: Int, hasSelection: Boolean) { + selectionChangedListener?.onSelectionChanged(start, end, hasSelection) + } + companion object { const val TAG = "CodeEditorView" diff --git a/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeTextView.kt b/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeTextView.kt index 2822352..aed0de2 100644 --- a/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeTextView.kt +++ b/library/src/main/java/de/markusressel/kodeeditor/library/view/CodeTextView.kt @@ -42,6 +42,11 @@ constructor(context: Context, initSyntaxHighlighter() } + /** + * Listener for selection changes + */ + var selectionChangedListener: SelectionChangedListener? = null + private var highlightingTimeout = 50L to TimeUnit.MILLISECONDS private var highlightingDisposable: Disposable? = null @@ -119,6 +124,11 @@ constructor(context: Context, } } + override fun onSelectionChanged(selStart: Int, selEnd: Int) { + super.onSelectionChanged(selStart, selEnd) + selectionChangedListener?.onSelectionChanged(selStart, selEnd, hasSelection()) + } + companion object { const val TAG = "CodeTextView" } diff --git a/library/src/main/java/de/markusressel/kodeeditor/library/view/SelectionChangedListener.kt b/library/src/main/java/de/markusressel/kodeeditor/library/view/SelectionChangedListener.kt new file mode 100644 index 0000000..6b372ea --- /dev/null +++ b/library/src/main/java/de/markusressel/kodeeditor/library/view/SelectionChangedListener.kt @@ -0,0 +1,17 @@ +package de.markusressel.kodeeditor.library.view + +/** + * Interface for a listener of selection changes + */ +interface SelectionChangedListener { + + /** + * Called when the selection changes + * + * @param start selection start index + * @param end selection end index + * @param hasSelection true when a range is selected (start != end) + */ + fun onSelectionChanged(start: Int, end: Int, hasSelection: Boolean) + +} \ No newline at end of file From daf252db0c8224e18aca1327764459ba798f718b Mon Sep 17 00:00:00 2001 From: Markus Ressel Date: Sun, 10 Feb 2019 04:33:58 +0100 Subject: [PATCH 3/3] typo fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5bd3622..933149a 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ some of those methods you need to access the matching property of the `KodeEdito | Name | Description | Type | |------|-------------|------| | text | Sets the given text in the editor. | String | -| setText(@StringRes) | Sets the given strint resource as the text in the editor. | Int | +| setText(@StringRes) | Sets the given string resource as the text in the editor. | Int | | syntaxHighlighter | Gets/Sets the active syntax highlighter. Use `null` to disable highlighting altogether. | SyntaxHighlighter? | | editable | Gets/Sets if the editor content is editable. | Boolean | @@ -190,7 +190,7 @@ To acces these API methods use the `codeEditorLayout.codeEditorView` property. | Name | Description | Type | |------|-------------|------| | text | Sets the given text in the editor. | String | -| setText(@StringRes) | Sets the given strint resource as the text in the editor. | Int | +| setText(@StringRes) | Sets the given string resource as the text in the editor. | Int | | getLineCount() | Returns the current line count. | Long | | syntaxHighlighter | Gets/Sets the active syntax highlighter. Use `null` to disable highlighting altogether. | SyntaxHighlighter? | | editable | Gets/Sets if the editor content is editable. | Boolean |