Feature: A new DSL for ColorScheme and ExtraKeysView and even more in future
This commit is contained in:
@ -1,10 +0,0 @@
|
||||
package io.neolang
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
object Version {
|
||||
const val MAJOR = 0
|
||||
const val MINOR = 1
|
||||
const val PATCH = 0
|
||||
}
|
13
NeoLang/src/main/java/io/neolang/ast/NeoLangAttributeNode.kt
Normal file
13
NeoLang/src/main/java/io/neolang/ast/NeoLangAttributeNode.kt
Normal file
@ -0,0 +1,13 @@
|
||||
package io.neolang.ast
|
||||
|
||||
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangAttributeNode(private val stringNode: NeoLangStringNode, private val blockNode: NeoLangBlockNode) : NeoLangAstBaseNode() {
|
||||
|
||||
override fun toString(): String {
|
||||
return "NeoLangAttributeNode { stringNode: $stringNode, block: $blockNode }"
|
||||
}
|
||||
}
|
15
NeoLang/src/main/java/io/neolang/ast/NeoLangBlockNode.kt
Normal file
15
NeoLang/src/main/java/io/neolang/ast/NeoLangBlockNode.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package io.neolang.ast
|
||||
|
||||
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||
import io.neolang.ast.typed.NeoLangAstTypedNode
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangBlockNode(ast: NeoLangAstBaseNode) : NeoLangAstTypedNode(ast) {
|
||||
companion object {
|
||||
fun emptyNode() :NeoLangBlockNode {
|
||||
return NeoLangBlockNode(NeoLangDummyNode())
|
||||
}
|
||||
}
|
||||
}
|
8
NeoLang/src/main/java/io/neolang/ast/NeoLangDummyNode.kt
Normal file
8
NeoLang/src/main/java/io/neolang/ast/NeoLangDummyNode.kt
Normal file
@ -0,0 +1,8 @@
|
||||
package io.neolang.ast
|
||||
|
||||
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangDummyNode : NeoLangAstBaseNode()
|
6
NeoLang/src/main/java/io/neolang/ast/NeoLangEOFToken.kt
Normal file
6
NeoLang/src/main/java/io/neolang/ast/NeoLangEOFToken.kt
Normal file
@ -0,0 +1,6 @@
|
||||
package io.neolang.ast
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangEOFToken : NeoLangToken(NeoLangTokenType.EOF, NeoLangTokenValue.EOF)
|
13
NeoLang/src/main/java/io/neolang/ast/NeoLangGroupNode.kt
Normal file
13
NeoLang/src/main/java/io/neolang/ast/NeoLangGroupNode.kt
Normal file
@ -0,0 +1,13 @@
|
||||
package io.neolang.ast
|
||||
|
||||
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangGroupNode(private val attributes: List<NeoLangAttributeNode>) : NeoLangAstBaseNode() {
|
||||
|
||||
override fun toString(): String {
|
||||
return "NeoLangGroupNode { attrs: $attributes }"
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package io.neolang.ast
|
||||
|
||||
import io.neolang.ast.typed.NeoLangTokenTypedNode
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangNumberNode(token: NeoLangToken) : NeoLangTokenTypedNode(token)
|
21
NeoLang/src/main/java/io/neolang/ast/NeoLangProgramNode.kt
Normal file
21
NeoLang/src/main/java/io/neolang/ast/NeoLangProgramNode.kt
Normal file
@ -0,0 +1,21 @@
|
||||
package io.neolang.ast
|
||||
|
||||
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
class NeoLangProgramNode(private val groups: List<NeoLangGroupNode>) : NeoLangAstBaseNode() {
|
||||
|
||||
override fun toString(): String {
|
||||
return "NeoLangProgramNode { groups: $groups }"
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun emptyNode() : NeoLangProgramNode {
|
||||
return NeoLangProgramNode(listOf())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
package io.neolang.ast
|
||||
|
||||
import io.neolang.ast.typed.NeoLangTokenTypedNode
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangStringNode(token: NeoLangToken) : NeoLangTokenTypedNode(token)
|
13
NeoLang/src/main/java/io/neolang/ast/NeoLangToken.kt
Normal file
13
NeoLang/src/main/java/io/neolang/ast/NeoLangToken.kt
Normal file
@ -0,0 +1,13 @@
|
||||
package io.neolang.ast
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
open class NeoLangToken(val tokenType: NeoLangTokenType, val tokenValue: NeoLangTokenValue) {
|
||||
var lineNumber = 0
|
||||
|
||||
override fun toString(): String {
|
||||
return "Token { tokenType: $tokenType, tokenValue: $tokenValue };"
|
||||
}
|
||||
}
|
16
NeoLang/src/main/java/io/neolang/ast/NeoLangTokenType.kt
Normal file
16
NeoLang/src/main/java/io/neolang/ast/NeoLangTokenType.kt
Normal file
@ -0,0 +1,16 @@
|
||||
package io.neolang.ast
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
|
||||
enum class NeoLangTokenType {
|
||||
NUMBER,
|
||||
STRING,
|
||||
BRACKET_START,
|
||||
BRACKET_END,
|
||||
COLON,
|
||||
QUOTE,
|
||||
EOL,
|
||||
EOF,
|
||||
}
|
24
NeoLang/src/main/java/io/neolang/ast/NeoLangTokenValue.kt
Normal file
24
NeoLang/src/main/java/io/neolang/ast/NeoLangTokenValue.kt
Normal file
@ -0,0 +1,24 @@
|
||||
package io.neolang.ast
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
enum class NeoLangTokenValue(val value: String) {
|
||||
COLON(":"),
|
||||
BRACKET_START("{"),
|
||||
BRACKET_END("}"),
|
||||
QUOTE("\""),
|
||||
EOF("");
|
||||
|
||||
companion object {
|
||||
fun wrap(tokenText: String): NeoLangTokenValue {
|
||||
return when (tokenText) {
|
||||
COLON.value -> COLON
|
||||
BRACKET_START.value -> BRACKET_START
|
||||
BRACKET_END.value -> BRACKET_END
|
||||
QUOTE.value -> QUOTE
|
||||
else -> EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
NeoLang/src/main/java/io/neolang/ast/base/NeoLangAst.kt
Normal file
12
NeoLang/src/main/java/io/neolang/ast/base/NeoLangAst.kt
Normal file
@ -0,0 +1,12 @@
|
||||
package io.neolang.ast.base
|
||||
|
||||
import io.neolang.ast.visitor.NeoLangAstVisitor
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class NeoLangAst {
|
||||
fun visit(): NeoLangAstVisitor {
|
||||
return NeoLangAstVisitor(this)
|
||||
}
|
||||
}
|
3
NeoLang/src/main/java/io/neolang/ast/base/NeoLangAstBaseNode.kt
Executable file
3
NeoLang/src/main/java/io/neolang/ast/base/NeoLangAstBaseNode.kt
Executable file
@ -0,0 +1,3 @@
|
||||
package io.neolang.ast.base
|
||||
|
||||
open class NeoLangAstBaseNode : NeoLangAst()
|
@ -0,0 +1,12 @@
|
||||
package io.neolang.ast.typed
|
||||
|
||||
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class NeoLangAstTypedNode(val ast: NeoLangAstBaseNode) : NeoLangAstBaseNode() {
|
||||
override fun toString(): String {
|
||||
return "${javaClass.simpleName} { ast: $ast }"
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package io.neolang.ast.typed
|
||||
|
||||
import io.neolang.ast.base.NeoLangAstBaseNode
|
||||
import io.neolang.ast.NeoLangToken
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class NeoLangTokenTypedNode(val token: NeoLangToken) : NeoLangAstBaseNode() {
|
||||
override fun toString(): String {
|
||||
return "${javaClass.simpleName} { token: $token }"
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package io.neolang.ast.visitor
|
||||
|
||||
import io.neolang.ast.base.NeoLangAst
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class NeoLangAstVisitor(ast: NeoLangAst)
|
@ -0,0 +1,6 @@
|
||||
package io.neolang.parser
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class InvalidTokenException(message: String) : ParseException(message)
|
133
NeoLang/src/main/java/io/neolang/parser/NeoLangLexer.kt
Executable file
133
NeoLang/src/main/java/io/neolang/parser/NeoLangLexer.kt
Executable file
@ -0,0 +1,133 @@
|
||||
package io.neolang.parser
|
||||
|
||||
import io.neolang.ast.NeoLangEOFToken
|
||||
import io.neolang.ast.NeoLangToken
|
||||
import io.neolang.ast.NeoLangTokenType
|
||||
import io.neolang.ast.NeoLangTokenValue
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* grammar: [
|
||||
* prog: group (group)*
|
||||
* group: attribute (attribute)*
|
||||
* attribute: TEXT COLON block
|
||||
* block: NUMBER | TEXT | (BRACKET_START group BRACKET_STOP)
|
||||
* ]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangLexer {
|
||||
private var programCode: String? = null
|
||||
private var currentPosition: Int = 0
|
||||
private var currentChar: Char = ' '
|
||||
private var lineNumber = 0
|
||||
|
||||
internal fun setInputSource(programCode: String?) {
|
||||
this.programCode = programCode
|
||||
}
|
||||
|
||||
internal fun lex(): List<NeoLangToken> {
|
||||
val programCode = this.programCode ?: return listOf()
|
||||
currentPosition = 0
|
||||
lineNumber = 1
|
||||
currentChar = programCode[currentPosition]
|
||||
|
||||
val tokens = ArrayList<NeoLangToken>()
|
||||
while (currentPosition < programCode.length) {
|
||||
val token = nextToken
|
||||
if (token is NeoLangEOFToken) {
|
||||
break
|
||||
}
|
||||
tokens.add(token)
|
||||
}
|
||||
return tokens
|
||||
}
|
||||
|
||||
private fun moveToNextChar(): Boolean {
|
||||
val programCode = this.programCode ?: return false
|
||||
currentPosition++
|
||||
if (currentPosition >= programCode.length) {
|
||||
return false
|
||||
} else {
|
||||
currentChar = programCode[currentPosition]
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
private val nextToken: NeoLangToken
|
||||
get() {
|
||||
val programCode = this.programCode ?: return NeoLangEOFToken()
|
||||
|
||||
while (currentChar == ' '
|
||||
|| currentChar == '\t'
|
||||
|| currentChar == '\n'
|
||||
|| currentChar == '\r') {
|
||||
if (currentChar == '\n') {
|
||||
++lineNumber
|
||||
}
|
||||
// Skip white chars
|
||||
moveToNextChar()
|
||||
}
|
||||
|
||||
if (currentPosition >= programCode.length) {
|
||||
return NeoLangEOFToken()
|
||||
}
|
||||
|
||||
val currentToken = NeoLangTokenValue.wrap(currentChar.toString())
|
||||
val token: NeoLangToken = when (currentToken) {
|
||||
NeoLangTokenValue.COLON -> {
|
||||
moveToNextChar()
|
||||
NeoLangToken(NeoLangTokenType.COLON, currentToken)
|
||||
}
|
||||
NeoLangTokenValue.BRACKET_START -> {
|
||||
moveToNextChar()
|
||||
NeoLangToken(NeoLangTokenType.BRACKET_START, currentToken)
|
||||
}
|
||||
NeoLangTokenValue.BRACKET_END -> {
|
||||
moveToNextChar()
|
||||
NeoLangToken(NeoLangTokenType.BRACKET_END, currentToken)
|
||||
}
|
||||
NeoLangTokenValue.QUOTE -> {
|
||||
moveToNextChar()
|
||||
NeoLangToken(NeoLangTokenType.QUOTE, currentToken)
|
||||
}
|
||||
else -> {
|
||||
if (Character.isDigit(currentChar)) {
|
||||
NeoLangToken(NeoLangTokenType.NUMBER, NeoLangTokenValue.wrap(getNextTokenAsNumber()))
|
||||
} else if (Character.isLetterOrDigit(currentChar)) {
|
||||
NeoLangToken(NeoLangTokenType.STRING, NeoLangTokenValue.wrap(getNextTokenAsString()))
|
||||
} else {
|
||||
throw InvalidTokenException("Unexpected character: " + currentChar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
token.lineNumber = lineNumber
|
||||
return token
|
||||
}
|
||||
|
||||
private fun getNextTokenAsNumber(): String {
|
||||
return buildString {
|
||||
while (Character.isDigit(currentChar)) {
|
||||
append(currentChar)
|
||||
if (!moveToNextChar()) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNextTokenAsString(): String {
|
||||
return buildString {
|
||||
while (Character.isLetterOrDigit(currentChar)) {
|
||||
append(currentChar)
|
||||
if (!moveToNextChar()) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
134
NeoLang/src/main/java/io/neolang/parser/NeoLangParser.kt
Executable file
134
NeoLang/src/main/java/io/neolang/parser/NeoLangParser.kt
Executable file
@ -0,0 +1,134 @@
|
||||
package io.neolang.parser
|
||||
|
||||
import io.neolang.ast.*
|
||||
import io.neolang.ast.base.NeoLangAst
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class NeoLangParser {
|
||||
var ast: NeoLangAst? = null
|
||||
private set
|
||||
|
||||
private val lexer = NeoLangLexer()
|
||||
private var tokens = mutableListOf<NeoLangToken>()
|
||||
private var currentPosition: Int = 0
|
||||
private var currentToken: NeoLangToken? = null
|
||||
|
||||
fun setInputSource(programCode: String?) {
|
||||
lexer.setInputSource(programCode)
|
||||
}
|
||||
|
||||
fun parse(): NeoLangAst {
|
||||
updateParserStatus(lexer.lex())
|
||||
return ast ?: throw ParseException("AST is null")
|
||||
}
|
||||
|
||||
private fun updateParserStatus(tokens: List<NeoLangToken>) {
|
||||
if (tokens.isEmpty()) {
|
||||
throw ParseException("Input tokens must be non-empty")
|
||||
}
|
||||
this.tokens.clear()
|
||||
this.tokens.addAll(tokens)
|
||||
currentPosition = 0
|
||||
currentToken = tokens[currentPosition]
|
||||
ast = program()
|
||||
}
|
||||
|
||||
private fun match(tokenType: NeoLangTokenType, errorThrow: Boolean = false): Boolean {
|
||||
val currentToken = this.currentToken ?: throw InvalidTokenException("Unexpected token: null")
|
||||
|
||||
if (currentToken.tokenType === tokenType) {
|
||||
currentPosition++
|
||||
if (currentPosition >= tokens.size) {
|
||||
this.currentToken = NeoLangToken(NeoLangTokenType.EOF, NeoLangTokenValue.EOF)
|
||||
} else {
|
||||
this.currentToken = tokens[currentPosition]
|
||||
}
|
||||
return true
|
||||
|
||||
} else if (errorThrow) {
|
||||
throw InvalidTokenException("Unexpected token type " +
|
||||
"`${currentToken.tokenType}' near line ${currentToken.lineNumber}, " +
|
||||
"expected $tokenType")
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun program(): NeoLangProgramNode {
|
||||
val token = currentToken
|
||||
|
||||
var group = group()
|
||||
if (group != null) {
|
||||
val groups = mutableListOf(group)
|
||||
while (token?.tokenType !== NeoLangTokenType.EOF) {
|
||||
group = group()
|
||||
if (group == null) {
|
||||
break
|
||||
}
|
||||
groups.add(group)
|
||||
}
|
||||
return NeoLangProgramNode(groups)
|
||||
}
|
||||
|
||||
return NeoLangProgramNode.emptyNode()
|
||||
}
|
||||
|
||||
private fun group(): NeoLangGroupNode? {
|
||||
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
|
||||
|
||||
var attr = attribute()
|
||||
if (attr != null) {
|
||||
val attributes = mutableListOf(attr)
|
||||
|
||||
while (token.tokenType !== NeoLangTokenType.EOF
|
||||
&& token.tokenType !== NeoLangTokenType.BRACKET_END) {
|
||||
attr = attribute()
|
||||
if (attr == null) {
|
||||
break
|
||||
}
|
||||
attributes.add(attr)
|
||||
}
|
||||
return NeoLangGroupNode(attributes)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun attribute(): NeoLangAttributeNode? {
|
||||
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
|
||||
if (match(NeoLangTokenType.STRING)) {
|
||||
match(NeoLangTokenType.COLON, errorThrow = true)
|
||||
val block = block() ?: NeoLangBlockNode.emptyNode()
|
||||
return NeoLangAttributeNode(NeoLangStringNode(token), block)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun block(): NeoLangBlockNode? {
|
||||
val token = currentToken ?: throw InvalidTokenException("Unexpected token: null")
|
||||
when (token.tokenType) {
|
||||
NeoLangTokenType.NUMBER -> {
|
||||
match(NeoLangTokenType.NUMBER, errorThrow = true)
|
||||
return NeoLangBlockNode(NeoLangNumberNode(token))
|
||||
}
|
||||
NeoLangTokenType.STRING -> {
|
||||
match(NeoLangTokenType.STRING, errorThrow = true)
|
||||
return NeoLangBlockNode(NeoLangStringNode(token))
|
||||
}
|
||||
NeoLangTokenType.BRACKET_START -> {
|
||||
match(NeoLangTokenType.BRACKET_START, errorThrow = true)
|
||||
val group = group()
|
||||
match(NeoLangTokenType.BRACKET_END, errorThrow = true)
|
||||
|
||||
// Allow empty blocks
|
||||
return if (group != null) NeoLangBlockNode(group) else NeoLangBlockNode.emptyNode()
|
||||
}
|
||||
|
||||
else -> throw InvalidTokenException("Unexpected token `$token' for block, " +
|
||||
"expected `${NeoLangTokenType.NUMBER}', `${NeoLangTokenType.STRING}' or `${NeoLangTokenType.BRACKET_START}'")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package io.neolang.parser
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
open class ParseException(message: String) : RuntimeException(message)
|
@ -1,10 +0,0 @@
|
||||
package io.neolang.token
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class Token {
|
||||
lateinit var type: TokenType
|
||||
lateinit var value: Any
|
||||
lateinit var nextToken: Token
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
package io.neolang.token
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
enum class TokenType {
|
||||
TYPE_IDENTIFIER,
|
||||
TYPE_STRING,
|
||||
TYPE_INTEGER,
|
||||
TYPE_BOOLEAN,
|
||||
|
||||
KEYWORD_DOLLAR, /* $ */
|
||||
KEYWORD_USE /* @ */,
|
||||
|
||||
OPERATOR_BEGIN,
|
||||
OPT_ADD, /* + */
|
||||
OPT_SUB, /* - */
|
||||
OPT_NAV, /* - (负号) */
|
||||
OPT_MUL, /* * */
|
||||
OPT_DIV, /* / */
|
||||
OPT_MOD, /* % */
|
||||
OPT_XOR, /* ^ */
|
||||
OPT_AND, /* & */
|
||||
OPT_OR, /* | */
|
||||
LEFT_SHIFT, /* << */
|
||||
RIGHT_SHIFT, /* >> */
|
||||
OPERATOR_END,
|
||||
|
||||
LOGICAL_OPERATOR_BEGIN,
|
||||
OPT_LAND, /* && */
|
||||
OPT_LOR, /* || */
|
||||
OPT_LE, /* <= */
|
||||
OPT_LT, /* < */
|
||||
OPT_GE, /* >= */
|
||||
OPT_GT, /* > */
|
||||
OPT_EQ, /* == */
|
||||
OPT_NEQ, /* != */
|
||||
OPT_NOT, /* ! */
|
||||
LOGICAL_OPERATOR_END,
|
||||
}
|
@ -55,5 +55,6 @@ dependencies {
|
||||
compile 'com.github.wrdlbrnft:sorted-list-adapter:0.2.0.19'
|
||||
compile 'com.simplecityapps:recyclerview-fastscroll:1.0.16'
|
||||
// compile 'com.ramotion.cardslider:card-slider:0.1.0'
|
||||
compile 'com.github.igalata:Bubble-Picker:v0.2.4'
|
||||
// compile 'com.github.igalata:Bubble-Picker:v0.2.4'
|
||||
implementation project(path: ':NeoLang')
|
||||
}
|
||||
|
@ -1,88 +1,30 @@
|
||||
package io.neoterm.ui.setup
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.widget.Button
|
||||
import android.widget.Toast
|
||||
import com.igalata.bubblepicker.BubblePickerListener
|
||||
import com.igalata.bubblepicker.adapter.BubblePickerAdapter
|
||||
import com.igalata.bubblepicker.model.BubbleGradient
|
||||
import com.igalata.bubblepicker.model.PickerItem
|
||||
import com.igalata.bubblepicker.rendering.BubblePicker
|
||||
import io.neoterm.R
|
||||
import io.neoterm.backend.TerminalSession
|
||||
import io.neoterm.customize.pm.NeoPackageManager
|
||||
import io.neoterm.customize.pm.NeoPackageManagerUtils
|
||||
import io.neoterm.customize.setup.BaseFileInstaller
|
||||
import io.neoterm.preference.NeoPreference
|
||||
import io.neoterm.preference.NeoTermPath
|
||||
import io.neoterm.utils.PackageUtils
|
||||
import io.neoterm.frontend.floating.TerminalDialog
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* @author kiva
|
||||
*/
|
||||
class SetupActivity : AppCompatActivity() {
|
||||
companion object {
|
||||
private val DEFAULT_PACKAGES = arrayOf(
|
||||
"zsh", "neoterm-core", "tmux", "nodejs",
|
||||
"fish", "make", "gdb", "clang", "vim", "emacs", "nano",
|
||||
"curl", "git", "python", "p7zip", "oh-my-zsh")
|
||||
}
|
||||
|
||||
lateinit var picker: BubblePicker
|
||||
lateinit var toast: Toast
|
||||
var aptUpdated = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.ui_setup)
|
||||
picker = findViewById(R.id.bubble_picker) as BubblePicker
|
||||
val nextButton = findViewById(R.id.setup_next) as Button
|
||||
nextButton.setOnClickListener {
|
||||
if (aptUpdated) {
|
||||
val packageList = mutableListOf("apt", "install", "-y")
|
||||
var withShell: String? = null
|
||||
picker.selectedItems
|
||||
.filterNotNull()
|
||||
.forEach {
|
||||
val name = it.title ?: ""
|
||||
packageList.add(name)
|
||||
if (name == "zsh" || name == "fish" || name == "bash"
|
||||
|| name == "mosh" || name == "dash") {
|
||||
withShell = name
|
||||
}
|
||||
}
|
||||
if (packageList.size == 0) {
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
TerminalDialog(this@SetupActivity)
|
||||
.onFinish(object : TerminalDialog.SessionFinishedCallback {
|
||||
override fun onSessionFinished(dialog: TerminalDialog, finishedSession: TerminalSession?) {
|
||||
if (finishedSession?.exitStatus == 0) {
|
||||
dialog.dismiss()
|
||||
if (withShell != null) {
|
||||
NeoPreference.setLoginShell(withShell!!)
|
||||
}
|
||||
} else {
|
||||
dialog.setTitle(getString(R.string.error))
|
||||
}
|
||||
}
|
||||
})
|
||||
.execute(NeoTermPath.APT_BIN_PATH, packageList.toTypedArray())
|
||||
.show(getString(R.string.installer_message))
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
setupBubbles()
|
||||
installBaseFiles()
|
||||
}
|
||||
|
||||
@ -132,84 +74,31 @@ class SetupActivity : AppCompatActivity() {
|
||||
})
|
||||
}
|
||||
|
||||
@SuppressLint("ShowToast")
|
||||
private fun setupBubbles() {
|
||||
val titles =
|
||||
if (intent.getBooleanExtra("setup", false))
|
||||
DEFAULT_PACKAGES
|
||||
else
|
||||
randomPackageList()
|
||||
val colors = resources.obtainTypedArray(R.array.bubble_colors)
|
||||
|
||||
toast = Toast.makeText(this, null, Toast.LENGTH_LONG)
|
||||
|
||||
picker.bubbleSize = 25
|
||||
picker.adapter = object : BubblePickerAdapter {
|
||||
override val totalCount = titles.size
|
||||
override fun getItem(position: Int): PickerItem {
|
||||
return PickerItem().apply {
|
||||
title = titles[position]
|
||||
textColor = ContextCompat.getColor(this@SetupActivity, android.R.color.white)
|
||||
gradient = BubbleGradient(colors.getColor((position * 2) % 8, 0),
|
||||
colors.getColor((position * 2) % 8 + 1, 0), BubbleGradient.VERTICAL)
|
||||
}
|
||||
}
|
||||
}
|
||||
picker.listener = object : BubblePickerListener {
|
||||
override fun onBubbleSelected(item: PickerItem) {
|
||||
val packageName = item.title
|
||||
val pm = NeoPackageManager.get()
|
||||
val packageInfo = pm.getPackageInfo(packageName)
|
||||
if (packageInfo != null) {
|
||||
val packageDesc = packageInfo.description
|
||||
toast.cancel()
|
||||
toast.setText(packageDesc)
|
||||
toast.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBubbleDeselected(item: PickerItem) {
|
||||
toast.cancel()
|
||||
}
|
||||
}
|
||||
colors.recycle()
|
||||
}
|
||||
|
||||
private fun randomPackageList(): Array<String> {
|
||||
val list = mutableListOf<String>()
|
||||
val pm = NeoPackageManager.get()
|
||||
|
||||
val sourceFiles = NeoPackageManagerUtils.detectSourceFiles()
|
||||
pm.clearPackages()
|
||||
for (index in sourceFiles.indices) {
|
||||
pm.refreshPackageList(sourceFiles[index], false)
|
||||
}
|
||||
|
||||
val limit = DEFAULT_PACKAGES.size
|
||||
val packageNames = pm.packages.keys
|
||||
val packageCount = packageNames.size
|
||||
val random = Random()
|
||||
|
||||
var i = 0
|
||||
while (i < limit) {
|
||||
val randomIndex = Math.abs(random.nextInt()) % packageCount
|
||||
val packageName = packageNames.elementAt(randomIndex)
|
||||
if (packageName.startsWith("lib") || packageName.endsWith("-dev")) {
|
||||
continue
|
||||
}
|
||||
list.add(packageName)
|
||||
++i
|
||||
}
|
||||
return list.toTypedArray()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
picker.onResume()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
picker.onPause()
|
||||
}
|
||||
// private fun randomPackageList(): Array<String> {
|
||||
// val list = mutableListOf<String>()
|
||||
// val pm = NeoPackageManager.get()
|
||||
//
|
||||
// val sourceFiles = NeoPackageManagerUtils.detectSourceFiles()
|
||||
// pm.clearPackages()
|
||||
// for (index in sourceFiles.indices) {
|
||||
// pm.refreshPackageList(sourceFiles[index], false)
|
||||
// }
|
||||
//
|
||||
// val limit = 20
|
||||
// val packageNames = pm.packages.keys
|
||||
// val packageCount = packageNames.size
|
||||
// val random = Random()
|
||||
//
|
||||
// var i = 0
|
||||
// while (i < limit) {
|
||||
// val randomIndex = Math.abs(random.nextInt()) % packageCount
|
||||
// val packageName = packageNames.elementAt(randomIndex)
|
||||
// if (packageName.startsWith("lib") || packageName.endsWith("-dev")) {
|
||||
// continue
|
||||
// }
|
||||
// list.add(packageName)
|
||||
// ++i
|
||||
// }
|
||||
// return list.toTypedArray()
|
||||
// }
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
app:backgroundColor="@android:color/white">
|
||||
android:background="@android:color/white">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/titleTextView"
|
||||
@ -28,18 +27,6 @@
|
||||
android:textColor="@color/colorAccent"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/hintTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_margin="14dp"
|
||||
android:gravity="center"
|
||||
android:lineSpacingMultiplier="1"
|
||||
android:text="@string/setup_info2"
|
||||
android:textColor="#9b9b9b"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/setup_next"
|
||||
android:layout_gravity="end"
|
||||
@ -52,9 +39,4 @@
|
||||
android:textColor="#9b9b9b"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.igalata.bubblepicker.rendering.BubblePicker
|
||||
android:id="@+id/bubble_picker"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</LinearLayout>
|
@ -1,21 +0,0 @@
|
||||
package io.neoterm
|
||||
|
||||
import io.neoterm.customize.pm.NeoPackageManager
|
||||
import io.neoterm.customize.pm.NeoPackageManagerUtils
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see [Testing documentation](http://d.android.com/tools/testing)
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun test_pkg_parser() {
|
||||
val prefix = NeoPackageManagerUtils.detectSourceFilePrefix("https://baidu.com:81")
|
||||
println(prefix)
|
||||
}
|
||||
}
|
||||
|
19
app/src/test/java/io/neoterm/NeoLangTest.kt
Normal file
19
app/src/test/java/io/neoterm/NeoLangTest.kt
Normal file
@ -0,0 +1,19 @@
|
||||
package io.neoterm
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see [Testing documentation](http://d.android.com/tools/testing)
|
||||
*/
|
||||
class NeoLangTest {
|
||||
@Test
|
||||
fun testNeoLangParser() {
|
||||
val parser = io.neolang.parser.NeoLangParser()
|
||||
parser.setInputSource("app: { x: {} \n x: hello \n a: 1111 \n x: { x: 123 } }")
|
||||
val ast = parser.parse()
|
||||
println(ast)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user