mirror of
https://github.com/tateisu/SubwayTooter
synced 2025-01-14 10:25:45 +01:00
misskeyでCW警告部分に同じメンションが複数回出現するバグを修正。シンタックスハイライトのバグ修正。
This commit is contained in:
parent
b262645afa
commit
9d5ec0a2dd
@ -37,7 +37,8 @@ object MisskeySyntaxHighlighter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val keywords = ArrayList<String>().apply {
|
// 識別子に対して既存の名前と一致するか調べるようになったので、もはやソートの必要はない
|
||||||
|
private val keywords = HashSet<String>().apply {
|
||||||
|
|
||||||
val _keywords = arrayOf(
|
val _keywords = arrayOf(
|
||||||
"true",
|
"true",
|
||||||
@ -130,8 +131,7 @@ object MisskeySyntaxHighlighter {
|
|||||||
// Snake
|
// Snake
|
||||||
addAll(_keywords.map { k -> k[0].toUpperCase() + k.substring(1) })
|
addAll(_keywords.map { k -> k[0].toUpperCase() + k.substring(1) })
|
||||||
|
|
||||||
// 長い順にソート
|
add("NaN")
|
||||||
sortWith(Comparator { a, b -> b.length - a.length })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Token(
|
private class Token(
|
||||||
@ -149,11 +149,10 @@ object MisskeySyntaxHighlighter {
|
|||||||
|
|
||||||
private val reLineComment = Pattern.compile("""\A//.*""")
|
private val reLineComment = Pattern.compile("""\A//.*""")
|
||||||
private val reBlockComment = Pattern.compile("""\A/\*.*?\*/""", Pattern.DOTALL)
|
private val reBlockComment = Pattern.compile("""\A/\*.*?\*/""", Pattern.DOTALL)
|
||||||
private val reLabel = Pattern.compile("""\A@[A-Z_-][A-Z0-9_-]*?""", Pattern.CASE_INSENSITIVE)
|
|
||||||
private val reNumber = Pattern.compile("""\A[+-]?[\d.]+""")
|
private val reNumber = Pattern.compile("""\A[+-]?[\d.]+""")
|
||||||
private val reMethod =
|
private val reLabel = Pattern.compile("""\A@([A-Z_-][A-Z0-9_-]*)""", Pattern.CASE_INSENSITIVE)
|
||||||
Pattern.compile("""\A([A-Z_][A-Z0-9_-]*?)\s*\(""", Pattern.CASE_INSENSITIVE)
|
private val reKeyword =
|
||||||
private val reProperty = Pattern.compile("""\A[a-zA-Z0-9_-]+""")
|
Pattern.compile("""\A([A-Z_-][A-Z0-9_-]*)([ \t]*\()?""", Pattern.CASE_INSENSITIVE)
|
||||||
|
|
||||||
private val elements = arrayOf(
|
private val elements = arrayOf(
|
||||||
|
|
||||||
@ -227,15 +226,25 @@ object MisskeySyntaxHighlighter {
|
|||||||
|
|
||||||
// label
|
// label
|
||||||
{ env : Env ->
|
{ env : Env ->
|
||||||
|
// 直前に識別子があればNG
|
||||||
|
val prev = if(env.pos <= 0) null else env.source[env.pos - 1]
|
||||||
|
if(prev?.isLetterOrDigit() == true) return@arrayOf null
|
||||||
|
|
||||||
val match = reLabel.matcher(env.remain)
|
val match = reLabel.matcher(env.remain)
|
||||||
if(! match.find()) return@arrayOf null
|
if(! match.find()) return@arrayOf null
|
||||||
Token(length = match.end(), color = 0xe9003f)
|
|
||||||
|
val end = match.end()
|
||||||
|
when{
|
||||||
|
// @user@host のように直後に@が続くのはNG
|
||||||
|
env.remain.length > end && env.remain[end] =='@' -> null
|
||||||
|
else->Token(length = match.end(), color = 0xe9003f)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// number
|
// number
|
||||||
{ env : Env ->
|
{ env : Env ->
|
||||||
val prev = if(env.pos <= 0) null else env.source[env.pos - 1]
|
val prev = if(env.pos <= 0) null else env.source[env.pos - 1]
|
||||||
if(prev?.isLetter() == true) return@arrayOf null
|
if(prev?.isLetterOrDigit() == true) return@arrayOf null
|
||||||
val match = reNumber.matcher(env.remain)
|
val match = reNumber.matcher(env.remain)
|
||||||
when {
|
when {
|
||||||
match.find() -> Token(length = match.end(), color = 0xae81ff)
|
match.find() -> Token(length = match.end(), color = 0xae81ff)
|
||||||
@ -243,58 +252,40 @@ object MisskeySyntaxHighlighter {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// nan
|
// method, property, keyword
|
||||||
{ env : Env ->
|
{ env : Env ->
|
||||||
|
// 直前の文字が識別子に使えるなら識別子の開始とはみなさない
|
||||||
val prev = if(env.pos <= 0) null else env.source[env.pos - 1]
|
val prev = if(env.pos <= 0) null else env.source[env.pos - 1]
|
||||||
if(prev?.isLetter() == true) return@arrayOf null
|
if(prev?.isLetterOrDigit() == true || prev == '_') return@arrayOf null
|
||||||
|
|
||||||
|
val match = reKeyword.matcher(env.remain)
|
||||||
|
if(! match.find()) return@arrayOf null
|
||||||
|
val kw = match.group(1)
|
||||||
|
val bracket = match.group(2)
|
||||||
|
|
||||||
when {
|
when {
|
||||||
env.remain.safeSubstring(3) == "NaN" ->
|
// メソッド呼び出しは対照が変数かプロパティかに関わらずメソッドの色になる
|
||||||
Token(length = 3, color = 0xae81ff)
|
bracket?.isNotEmpty() == true ->
|
||||||
else ->
|
Token(length = kw.length, color = 0x8964c1, italic = true)
|
||||||
null
|
|
||||||
|
// 変数や定数ではなくプロパティならプロパティの色になる
|
||||||
|
prev == '.' ->Token(length = kw.length, color = 0xa71d5d)
|
||||||
|
|
||||||
|
keywords.contains(kw) -> when(kw) {
|
||||||
|
|
||||||
|
// 定数
|
||||||
|
"true", "false", "null", "nil", "undefined" ,"NaN" ->
|
||||||
|
Token(length = kw.length, color = 0xae81ff)
|
||||||
|
|
||||||
|
// その他の予約語
|
||||||
|
else ->Token(length = kw.length, color = 0x2973b7)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 強調表示しないが、識別子単位で読み飛ばす
|
||||||
|
else -> Token(length = kw.length)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// method
|
|
||||||
{ env : Env ->
|
|
||||||
val match = reMethod.matcher(env.remain)
|
|
||||||
when {
|
|
||||||
match.find() -> Token(length = match.end(), color = 0x8964c1, italic = true)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// property
|
|
||||||
{ env : Env ->
|
|
||||||
val prev = if(env.pos <= 0) null else env.source[env.pos - 1]
|
|
||||||
if(prev != '.') return@arrayOf null
|
|
||||||
|
|
||||||
val match = reProperty.matcher(env.remain)
|
|
||||||
when {
|
|
||||||
match.find() -> Token(length = match.end(), color = 0xa71d5d)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// keyword
|
|
||||||
{ env : Env ->
|
|
||||||
val prev = if(env.pos <= 0) null else env.source[env.pos - 1]
|
|
||||||
if(prev?.isLetter() == true) return@arrayOf null
|
|
||||||
|
|
||||||
val match = keywords.find {
|
|
||||||
env.remain.safeSubstring(it.length) == it
|
|
||||||
} ?: return@arrayOf null
|
|
||||||
|
|
||||||
val kw = env.remain.safeSubstring(match.length)
|
|
||||||
when(kw) {
|
|
||||||
"true", "false", "null", "nil", "undefined" ->
|
|
||||||
Token(length = kw.length, color = 0xae81ff)
|
|
||||||
else ->
|
|
||||||
Token(length = kw.length, color = 0x2973b7)
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
// symbol
|
// symbol
|
||||||
{ env : Env ->
|
{ env : Env ->
|
||||||
when {
|
when {
|
||||||
@ -316,12 +307,12 @@ object MisskeySyntaxHighlighter {
|
|||||||
sb.append(source.substring(pos, end))
|
sb.append(source.substring(pos, end))
|
||||||
env.pos = end
|
env.pos = end
|
||||||
|
|
||||||
if( token.comment ) {
|
if(token.comment) {
|
||||||
sb.setSpan(
|
sb.setSpan(
|
||||||
ForegroundColorSpan(Color.BLACK or 0x808000)
|
ForegroundColorSpan(Color.BLACK or 0x808000)
|
||||||
, pos, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
, pos, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
|
||||||
)
|
)
|
||||||
}else{
|
} else {
|
||||||
var c = token.color
|
var c = token.color
|
||||||
if(c != 0) {
|
if(c != 0) {
|
||||||
if(c < 0x1000000) {
|
if(c < 0x1000000) {
|
||||||
@ -403,12 +394,13 @@ object MisskeyMarkdownDecoder {
|
|||||||
val text : String
|
val text : String
|
||||||
, var pos : Int
|
, var pos : Int
|
||||||
, var remain : String
|
, var remain : String
|
||||||
){
|
) {
|
||||||
|
|
||||||
internal fun genNode1(
|
internal fun genNode1(
|
||||||
type : NodeType,
|
type : NodeType,
|
||||||
sourceLength : Int,
|
sourceLength : Int,
|
||||||
data : ArrayList<String?>?
|
data : ArrayList<String?>?
|
||||||
) =Node(
|
) = Node(
|
||||||
type = type,
|
type = type,
|
||||||
sourceStart = pos,
|
sourceStart = pos,
|
||||||
sourceLength = sourceLength,
|
sourceLength = sourceLength,
|
||||||
@ -431,39 +423,40 @@ object MisskeyMarkdownDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val reLink = Pattern.compile("""^\??\[([^\[\]]+?)]\((https?://[\w/:%#@${'$'}&?!()\[\]~.=+\-]+?)\)""")
|
private val reLink =
|
||||||
|
Pattern.compile("""^\??\[([^\[\]]+?)]\((https?://[\w/:%#@${'$'}&?!()\[\]~.=+\-]+?)\)""")
|
||||||
|
|
||||||
private val reCodeInline = Pattern.compile("""^`(.+?)`""")
|
private val reCodeInline = Pattern.compile("""^`(.+?)`""")
|
||||||
|
|
||||||
private val reMention = Pattern.compile(
|
private val reMention = Pattern.compile(
|
||||||
"""^@([a-z0-9_]+)(?:@([a-z0-9.\-]+[a-z0-9]))?"""
|
"""^@([a-z0-9_]+)(?:@([a-z0-9.\-]+[a-z0-9]))?"""
|
||||||
,Pattern.CASE_INSENSITIVE
|
, Pattern.CASE_INSENSITIVE
|
||||||
)
|
)
|
||||||
|
|
||||||
private val reHashtag = Pattern.compile("""^#([^\s]+)""")
|
private val reHashtag = Pattern.compile("""^#([^\s]+)""")
|
||||||
|
|
||||||
private val reMotion1 = Pattern.compile("""^\Q(((\E(.+?)\Q)))\E""")
|
private val reMotion1 = Pattern.compile("""^\Q(((\E(.+?)\Q)))\E""")
|
||||||
private val reMotion2 = Pattern.compile("""^<motion>(.+?)</motion>""")
|
private val reMotion2 = Pattern.compile("""^<motion>(.+?)</motion>""")
|
||||||
|
|
||||||
private val nodeParserList = arrayOf(
|
private val nodeParserList = arrayOf(
|
||||||
|
|
||||||
// 処理順序に意味があるので入れ替えないこと
|
// 処理順序に意味があるので入れ替えないこと
|
||||||
// 記号列が長い順
|
// 記号列が長い順
|
||||||
simpleParser(
|
simpleParser(
|
||||||
NodeType.Big,
|
NodeType.Big,
|
||||||
Pattern.compile("""^\Q***\E(.+?)\Q***\E""")
|
Pattern.compile("""^\Q***\E(.+?)\Q***\E""")
|
||||||
),
|
),
|
||||||
|
|
||||||
simpleParser(
|
simpleParser(
|
||||||
NodeType.Bold,
|
NodeType.Bold,
|
||||||
Pattern.compile("""^\Q**\E(.+?)\Q**\E""")
|
Pattern.compile("""^\Q**\E(.+?)\Q**\E""")
|
||||||
),
|
),
|
||||||
|
|
||||||
simpleParser(
|
simpleParser(
|
||||||
NodeType.Title,
|
NodeType.Title,
|
||||||
Pattern.compile("""^[【\[](.+?)[】\]]\n""")
|
Pattern.compile("""^[【\[](.+?)[】\]]\n""")
|
||||||
),
|
),
|
||||||
|
|
||||||
simpleParser(
|
simpleParser(
|
||||||
NodeType.Url,
|
NodeType.Url,
|
||||||
Pattern.compile("""^(https?://[\w/:%#@${'$'}&?!()\[\]~.=+\-]+)""")
|
Pattern.compile("""^(https?://[\w/:%#@${'$'}&?!()\[\]~.=+\-]+)""")
|
||||||
@ -524,7 +517,7 @@ object MisskeyMarkdownDecoder {
|
|||||||
|
|
||||||
simpleParser(
|
simpleParser(
|
||||||
NodeType.CodeBlock,
|
NodeType.CodeBlock,
|
||||||
Pattern.compile("""^```(.+?)```""",Pattern.DOTALL)
|
Pattern.compile("""^```(.+?)```""", Pattern.DOTALL)
|
||||||
),
|
),
|
||||||
|
|
||||||
{ env : ParserEnv ->
|
{ env : ParserEnv ->
|
||||||
@ -561,7 +554,7 @@ object MisskeyMarkdownDecoder {
|
|||||||
NodeType.Search,
|
NodeType.Search,
|
||||||
Pattern.compile(
|
Pattern.compile(
|
||||||
"""^(.+?)[ ](検索|\[検索]|Search|\[Search])(\n|${'$'})"""
|
"""^(.+?)[ ](検索|\[検索]|Search|\[Search])(\n|${'$'})"""
|
||||||
,Pattern.CASE_INSENSITIVE
|
, Pattern.CASE_INSENSITIVE
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -650,7 +643,7 @@ object MisskeyMarkdownDecoder {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpannableStringBuilderEx : SpannableStringBuilder(){
|
class SpannableStringBuilderEx : SpannableStringBuilder() {
|
||||||
|
|
||||||
var mentions : ArrayList<TootMention>? = null
|
var mentions : ArrayList<TootMention>? = null
|
||||||
}
|
}
|
||||||
@ -807,7 +800,7 @@ object MisskeyMarkdownDecoder {
|
|||||||
|
|
||||||
val username = data?.get(0) ?: ""
|
val username = data?.get(0) ?: ""
|
||||||
val host = data?.get(1) ?: ""
|
val host = data?.get(1) ?: ""
|
||||||
|
|
||||||
val linkHelper = options.linkHelper
|
val linkHelper = options.linkHelper
|
||||||
if(linkHelper == null) {
|
if(linkHelper == null) {
|
||||||
appendText(
|
appendText(
|
||||||
@ -817,33 +810,38 @@ object MisskeyMarkdownDecoder {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
val shortAcct = when {
|
val shortAcct = when {
|
||||||
host.isEmpty()
|
host.isEmpty()
|
||||||
|| host.equals(linkHelper.host,ignoreCase = true) ->
|
|| host.equals(linkHelper.host, ignoreCase = true) ->
|
||||||
username
|
username
|
||||||
else ->
|
else ->
|
||||||
"$username@$host"
|
"$username@$host"
|
||||||
}
|
}
|
||||||
|
|
||||||
val userHost =when{
|
val userHost = when {
|
||||||
host.isEmpty() -> linkHelper.host
|
host.isEmpty() -> linkHelper.host
|
||||||
else -> host
|
else -> host
|
||||||
}
|
}
|
||||||
val userUrl = "https://$userHost/@$username"
|
val userUrl = "https://$userHost/@$username"
|
||||||
|
|
||||||
var mentions = sb.mentions
|
var mentions = sb.mentions
|
||||||
if( mentions == null ){
|
if(mentions == null) {
|
||||||
mentions = ArrayList()
|
mentions = ArrayList()
|
||||||
sb.mentions = mentions
|
sb.mentions = mentions
|
||||||
}
|
}
|
||||||
mentions.add(TootMention(
|
|
||||||
EntityIdLong(-1L)
|
if(mentions.find { it.acct == shortAcct } == null) {
|
||||||
,userUrl
|
mentions.add(
|
||||||
,shortAcct
|
TootMention(
|
||||||
,username
|
EntityIdLong(- 1L)
|
||||||
))
|
, userUrl
|
||||||
|
, shortAcct
|
||||||
|
, username
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
appendLink(
|
appendLink(
|
||||||
when {
|
when {
|
||||||
Pref.bpMentionFullAcct(App1.pref) -> "@$username@$userHost"
|
Pref.bpMentionFullAcct(App1.pref) -> "@$username@$userHost"
|
||||||
|
Loading…
Reference in New Issue
Block a user