[ad_1]
Squircle IDE is a quick and free multi-language code editor for Android.
EditorKit
- Gradle Dependency
- The Fundamentals
- Extra Choices
- Code Options
- Undo Redo
- Navigation
- Theming
- Customized Plugin
Languages
The editorkit
module gives code editor with none assist for programming languages.
If you’re upgrading from any older model, please take a look on the migration information.
Please be aware that this library solely helps Kotlin.
Gradle Dependency
Add this to your module’s construct.gradle
file:
dependencies {
...
implementation 'com.blacksquircle.ui:editorkit:2.1.2'
}
The editorkit
module doesn’t present assist for syntax highlighting, you have to add particular language dependency. You possibly can see checklist of obtainable languages right here.
The Fundamentals
First, you have to add TextProcessor
in your format:
<com.blacksquircle.ui.editorkit.widget.TextProcessor
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="prime|begin"
android:id="@+id/editor" />
Second, you have to present a Language
object to assist syntax highlighting by utilizing following code:
val editor = findViewById<TextProcessor>(R.id.editor)
editor.language = JavaScriptLanguage() // or some other language you need
Third, you have to name setTextContent
to set the textual content. Do not use the default setText
methodology.
editor.setTextContent("your code right here")
Additionally you may need to use setTextContent(PrecomputedTextCompat)
should you’re working with giant textual content information.
Lastly, after you set the textual content you have to clear undo/redo historical past since you do not need to maintain the change historical past of earlier file:
import com.blacksquircle.ui.editorkit.mannequin.UndoStack
editor.undoStack = UndoStack()
editor.redoStack = UndoStack()
Now you may start utilizing the code editor.
Extra Choices
Configuration
You possibly can change the default code editor conduct by utilizing Plugin DSL as proven beneath:
val pluginSupplier = PluginSupplier.create {
pinchZoom { // whether or not the zoom gesture enabled
minTextSize = 10f
maxTextSize = 20f
}
lineNumbers {
lineNumbers = true // line numbers visibility
highlightCurrentLine = true // whether or not the present line shall be highlighted
}
highlightDelimiters() // spotlight open/closed brackets beside the cursor
autoIndentation {
autoIndentLines = true // whether or not the auto indentation enabled
autoCloseBrackets = true // routinely shut open parenthesis/bracket/brace
autoCloseQuotes = true // routinely shut single/double quote when typing
}
}
editor.plugins(pluginSupplier)
To allow/disable plugins in runtime, encompass vital strategies with if (enabled) { ... }
operator:
val pluginSupplier = PluginSupplier.create {
if (preferences.isLineNumbersEnabled) {
lineNumbers()
}
if (preferences.isPinchZoomEnabled) {
pinchZoom()
}
// ...
}
editor.plugins(pluginSupplier)
Keep in mind: everytime you name editor.plugins(pluginSupplier)
it compares present plugin checklist with the brand new one, after which detaches plugins that does not exists within the PluginSupplier
.
Textual content Scroller
To connect the textual content scroller you have to add TextScroller
in format:
<com.blacksquircle.ui.editorkit.widget.TextScroller
android:layout_width="30dp"
android:layout_height="match_parent"
android:id="@+id/scroller"
app:thumbNormal="@drawable/fastscroll_normal"
app:thumbDragging="@drawable/fastscroll_pressed"
app:thumbTint="@shade/blue" />
Now you have to go a reference to a view inside attachTo
methodology:
val editor = findViewById<TextProcessor>(R.id.editor)
val scroller = findViewById<TextScroller>(R.id.scroller)
scroller.attachTo(editor)
// or utilizing Plugin DSL:
val pluginSupplier = PluginSupplier.create {
...
textScroller {
scroller = findViewById<TextScroller>(R.id.scroller)
}
}
Code Options
Whenever you working with a code editor you need to see the checklist of code suggestion. (Notice that it’s important to present a Language
object earlier than begin utilizing it.)
First, you have to create a format file that can symbolize the suggestion merchandise inside dropdown menu:
<!-- item_suggestion.xml -->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:padding="6dp"
android:textSize="12sp"
android:typeface="monospace"
android:id="@+id/title" />
Second, you have to create {custom} SuggestionAdapter
:
class AutoCompleteAdapter(context: Context) : SuggestionAdapter(context, R.format.item_suggestion) {
override enjoyable createViewHolder(mother or father: ViewGroup): SuggestionViewHolder {
val inflater = LayoutInflater.from(mother or father.context)
val view = inflater.inflate(R.format.item_suggestion, mother or father, false)
return AutoCompleteViewHolder(view)
}
class AutoCompleteViewHolder(itemView: View) : SuggestionViewHolder(itemView) {
non-public val title: TextView = itemView.findViewById(R.id.title)
override enjoyable bind(suggestion: Suggestion?, question: String) {
title.textual content = suggestion?.textual content
}
}
}
Third, allow the code completion plugin and set SuggestionAdapter
:
val pluginSupplier = PluginSupplier.create {
...
codeCompletion {
suggestionAdapter = AutoCompleteAdapter(this)
}
}
UPD: When you having an points with the popup place (e.g vertical offset), this is likely to be solved by explicitly setting android:dropDownAnchor in XML.
Undo Redo
The TextProcessor
helps undo/redo operations, however keep in mind that you should verify the power to undo/redo earlier than calling precise strategies:
// Undo
if (editor.canUndo()) {
editor.undo()
}
// Redo
if (editor.canRedo()) {
editor.redo()
}
Additionally you could have a use case while you need to replace undo/redo buttons visibility or different UI after the textual content replacements is finished, this may be achieved by including OnUndoRedoChangedListener
:
editor.onUndoRedoChangedListener = object : OnUndoRedoChangedListener {
override enjoyable onUndoRedoChanged() {
val canUndo = editor.canUndo()
val canRedo = editor.canRedo()
// ...
}
}
Navigation
Textual content Navigation
You should utilize these extension strategies to navigate in textual content:
editor.moveCaretToStartOfLine()
editor.moveCaretToEndOfLine()
editor.moveCaretToPrevWord()
editor.moveCaretToNextWord()
…or use «Go to Line» characteristic to put the caret on the particular line:
import com.blacksquircle.ui.editorkit.exception.LineException
attempt {
editor.gotoLine(lineNumber)
} catch (e: LineException) {
Toast.makeText(this, "Line doesn't exists", Toast.LENGTH_SHORT).present()
}
Discover and Change
The TextProcessor
has built-in assist for search and change operations, together with:
- Search ahead or backward
- Common Expressions
- Match Case
- Phrases Solely
The category itself comprises self-explanatory strategies for all of your looking out wants:
discover(params)
– Discover all attainable leads to textual content with supplied choices.replaceFindResult(replaceText)
– Finds present match and replaces it with new textual content.replaceAllFindResults(replaceText)
– Finds all matches and replaces them with the brand new textual content.findNext()
– Finds the following match and scrolls to it.findPrevious()
– Finds the earlier match and scrolls to it.clearFindResultSpans()
– Clears all discover spans on the display. Name this methodology while you’re accomplished looking out.
import com.blacksquircle.ui.editorkit.mannequin.FindParams
val params = FindParams(
question = "perform", // textual content to seek out
regex = false, // common expressions
matchCase = true, // case delicate
wordsOnly = true // phrases solely
)
editor.discover(params)
// To navigate between outcomes use findNext() and findPrevious()
Shortcuts
When you’re utilizing bluetooth keyboard you most likely need to use keyboard shortcuts to write down your code quicker. To assist the keyboard shortcuts you have to allow the shortcuts plugin and set OnShortcutListener
:
val pluginSupplier = PluginSupplier.create {
...
shortcuts {
onShortcutListener = object : OnShortcutListener {
override enjoyable onShortcut(shortcut: Shortcut): Boolean {
val (ctrl, shift, alt, keyCode) = shortcut
return when {
ctrl && keyCode == KeyEvent.KEYCODE_DPAD_LEFT -> editor.moveCaretToStartOfLine()
ctrl && keyCode == KeyEvent.KEYCODE_DPAD_RIGHT -> editor.moveCaretToEndOfLine()
alt && keyCode == KeyEvent.KEYCODE_DPAD_LEFT -> editor.moveCaretToPrevWord()
alt && keyCode == KeyEvent.KEYCODE_DPAD_RIGHT -> editor.moveCaretToNextWord()
// ...
else -> false
}
}
}
}
}
The onShortcut
methodology shall be invoked provided that at the least one in all following keys is pressed: ctrl, shift, alt.
You may already observed that it’s important to return a Boolean
worth as the results of onShortcut
methodology. Return true
if the listener has consumed the shortcut occasion, false
in any other case.
Theming
The editorkit
module contains some default themes within the EditorTheme
class:
editor.colorScheme = EditorTheme.DARCULA // default
// or you should utilize one in all these:
EditorTheme.MONOKAI
EditorTheme.OBSIDIAN
EditorTheme.LADIES_NIGHT
EditorTheme.TOMORROW_NIGHT
EditorTheme.VISUAL_STUDIO_2013
You too can write your individual theme by altering the ColorScheme
properties. The instance beneath reveals how one can programmatically load the colour scheme:
editor.colorScheme = ColorScheme(
textColor = Coloration.parseColor("#C8C8C8"),
backgroundColor = Coloration.parseColor("#232323"),
gutterColor = Coloration.parseColor("#2C2C2C"),
gutterDividerColor = Coloration.parseColor("#555555"),
gutterCurrentLineNumberColor = Coloration.parseColor("#FFFFFF"),
gutterTextColor = Coloration.parseColor("#C6C8C6"),
selectedLineColor = Coloration.parseColor("#141414"),
selectionColor = Coloration.parseColor("#454464"),
suggestionQueryColor = Coloration.parseColor("#4F98F7"),
findResultBackgroundColor = Coloration.parseColor("#1C3D6B"),
delimiterBackgroundColor = Coloration.parseColor("#616161"),
numberColor = Coloration.parseColor("#BACDAB"),
operatorColor = Coloration.parseColor("#DCDCDC"),
keywordColor = Coloration.parseColor("#669BD1"),
typeColor = Coloration.parseColor("#669BD1"),
langConstColor = Coloration.parseColor("#669BD1"),
preprocessorColor = Coloration.parseColor("#C49594"),
variableColor = Coloration.parseColor("#9DDDFF"),
methodColor = Coloration.parseColor("#71C6B1"),
stringColor = Coloration.parseColor("#CE9F89"),
commentColor = Coloration.parseColor("#6BA455"),
tagColor = Coloration.parseColor("#DCDCDC"),
tagNameColor = Coloration.parseColor("#669BD1"),
attrNameColor = Coloration.parseColor("#C8C8C8"),
attrValueColor = Coloration.parseColor("#CE9F89"),
entityRefColor = Coloration.parseColor("#BACDAB")
)
Customized Plugin
Since v2.1.0 the EditorKit library helps writing {custom} plugins to increase it is default performance. When you’re utilizing the newest model, you is likely to be acquainted with PluginSupplier
and know find out how to use it is DSL. See Extra Choices for information.
First, you have to create a category which extends the EditorPlugin
and supply it is id within the constructor:
class CustomPlugin : EditorPlugin("custom-plugin-id") {
var publicProperty = true
override enjoyable onAttached(editText: TextProcessor) {
tremendous.onAttached(editText)
// TODO allow your characteristic right here
}
override enjoyable onDetached(editText: TextProcessor) {
tremendous.onDetached(editText)
// TODO disable your characteristic right here
}
}
Second, you may override lifecycle strategies, for instance afterDraw
, which invoked instantly after onDraw(Canvas)
in code editor:
class CustomPlugin : EditorPlugin("custom-plugin-id") {
var publicProperty = true
non-public val dividerPaint = Paint().apply {
shade = Coloration.GRAY
}
override enjoyable afterDraw(canvas: Canvas?) {
tremendous.afterDraw(canvas)
if (publicProperty) {
var i = editText.topVisibleLine
whereas (i <= editText.bottomVisibleLine) {
val startX = editText.paddingStart + editText.scrollX
val startY = editText.paddingTop + editText.format.getLineBottom(i)
val stopX = editText.paddingLeft + editText.format.width + editText.paddingRight
val stopY = editText.paddingTop + editText.format.getLineBottom(i)
canvas?.drawLine( // draw divider for every seen line
startX.toFloat(), startY.toFloat(),
stopX.toFloat(), stopY.toFloat(),
dividerPaint
)
i++
}
}
}
}
Third, create an extension perform to enhance code readability when including your plugin to a PluginSupplier
:
enjoyable PluginSupplier.verticalDividers(block: CustomPlugin.() -> Unit = {}) {
plugin(CustomPlugin(), block)
}
Lastly, you may connect your plugin utilizing DSL:
val pluginSupplier = PluginSupplier.create {
verticalDividers {
publicProperty = true // whether or not ought to draw the dividers
}
...
}
editor.plugins(pluginSupplier)
The language modules gives assist for programming languages. This contains syntax highlighting, code strategies and supply code parser. (Notice that supply code parser at the moment works solely in language-javascript
module, however will probably be applied for extra languages quickly)
Gradle Dependency
Choose your language and add it is dependency to your module’s construct.gradle
file:
dependencies {
...
implementation 'com.blacksquircle.ui:language-actionscript:2.1.2'
implementation 'com.blacksquircle.ui:language-base:2.1.2' // for {custom} language
implementation 'com.blacksquircle.ui:language-c:2.1.2'
implementation 'com.blacksquircle.ui:language-cpp:2.1.2'
implementation 'com.blacksquircle.ui:language-csharp:2.1.2'
implementation 'com.blacksquircle.ui:language-groovy:2.1.2'
implementation 'com.blacksquircle.ui:language-html:2.1.2'
implementation 'com.blacksquircle.ui:language-java:2.1.2'
implementation 'com.blacksquircle.ui:language-javascript:2.1.2'
implementation 'com.blacksquircle.ui:language-json:2.1.2'
implementation 'com.blacksquircle.ui:language-julia:2.1.2'
implementation 'com.blacksquircle.ui:language-kotlin:2.1.2'
implementation 'com.blacksquircle.ui:language-lisp:2.1.2'
implementation 'com.blacksquircle.ui:language-lua:2.1.2'
implementation 'com.blacksquircle.ui:language-markdown:2.1.2'
implementation 'com.blacksquircle.ui:language-php:2.1.2'
implementation 'com.blacksquircle.ui:language-plaintext:2.1.2'
implementation 'com.blacksquircle.ui:language-python:2.1.2'
implementation 'com.blacksquircle.ui:language-ruby:2.1.2'
implementation 'com.blacksquircle.ui:language-shell:2.1.2'
implementation 'com.blacksquircle.ui:language-sql:2.1.2'
implementation 'com.blacksquircle.ui:language-typescript:2.1.2'
implementation 'com.blacksquircle.ui:language-visualbasic:2.1.2'
implementation 'com.blacksquircle.ui:language-xml:2.1.2'
}
Customized Language
First, add this to your module’s construct.gradle
file:
dependencies {
...
implementation 'com.blacksquircle.ui:language-base:2.1.2'
}
Second, implement the Language
interface:
import com.blacksquircle.ui.language.base.Language
import com.blacksquircle.ui.language.base.parser.LanguageParser
import com.blacksquircle.ui.language.base.supplier.SuggestionProvider
import com.blacksquircle.ui.language.base.styler.LanguageStyler
class CustomLanguage : Language {
override enjoyable getName(): String {
return "{custom} language"
}
override enjoyable getParser(): LanguageParser {
return CustomParser()
}
override enjoyable getProvider(): SuggestionProvider {
return CustomProvider()
}
override enjoyable getStyler(): LanguageStyler {
return CustomStyler()
}
}
Each language consist of three key elements:
- LanguageParser is accountable for analyzing the supply code. The code editor doesn’t use this element immediately.
- SuggestionProvider is accountable for amassing the names of features, fields, and key phrases inside your file scope. The code editor use this element to show the checklist of code strategies.
- LanguageStyler is accountable for syntax highlighting. The code editor use this element to show syntax spotlight spans on the display.
LanguageParser
LanguageParser
is an interface which detects syntax errors so you may show them within the TextProcessor
later.
To create a {custom} parser you have to implement execute
methodology that can return a ParseResult
.
If ParseResult
comprises an exception it signifies that the supply code cannot compile and comprises syntax errors. You possibly can spotlight an error line by calling editor.setErrorLine(lineNumber)
methodology.
Keep in mind that you just should not use this methodology on the principle thread.
class CustomParser : LanguageParser {
override enjoyable execute(identify: String, supply: String): ParseResult {
// TODO Implement parser
val lineNumber = 0
val columnNumber = 0
val parseException = ParseException("describe exception right here", lineNumber, columnNumber)
return ParseResult(parseException)
}
}
SuggestionProvider
SuggestionProvider
is an interface which gives code strategies to show them within the TextProcessor
.
The textual content scanning is finished on a per-line foundation. When the person edits code on a single line, that line is re-scanned by the present SuggestionsProvider
implementation, so you may maintain your strategies checklist updated. That is accomplished by calling the processLine
methodology. This methodology is accountable for parsing a line of textual content and saving the code strategies for that line.
After calling setTextContent
the code editor will name processLine
for every line to seek out all attainable code strategies.
class CustomProvider : SuggestionProvider {
// You should utilize WordsManager
// should you do not need to write the language-specific implementation
non-public val wordsManager = WordsManager()
override enjoyable getAll(): Set<Suggestion> {
return wordsManager.getWords()
}
override enjoyable processLine(lineNumber: Int, textual content: String) {
wordsManager.processLine(lineNumber, textual content)
}
override enjoyable deleteLine(lineNumber: Int) {
wordsManager.deleteLine(lineNumber)
}
override enjoyable clearLines() {
wordsManager.clearLines()
}
}
LanguageStyler
LanguageStyler
is an interface which gives syntax spotlight spans to show them within the TextProcessor
.
The execute
methodology shall be executed on the background thread each time the textual content adjustments. You should utilize regex or lexer to seek out the key phrases in textual content.
Keep in mind: the extra spans you add, the extra time it takes to render on the principle thread.
class CustomStyler : LanguageStyler {
override enjoyable execute(supply: String, scheme: ColorScheme): Listing<SyntaxHighlightSpan> {
val syntaxHighlightSpans = mutableListOf<SyntaxHighlightSpan>()
// TODO Implement syntax highlighting
return syntaxHighlightSpans
}
}
[ad_2]
Source_link