mirror of
https://github.com/house-of-vanity/desubot.git
synced 2025-07-08 04:54:08 +00:00
Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
3085d4c450 | |||
4b142ae8ef | |||
8f3cccf01d | |||
3136bce84f | |||
e09047bb5b | |||
5528177e52 | |||
ed32bd9195 | |||
d14aa3beb4 | |||
43e4f26af1 | |||
5d8d3441d2 | |||
34fa54e6f4 | |||
d5b30cc94e | |||
7a66034381 | |||
47906fe22d | |||
ea6d9b55a1 | |||
83a6045b18 | |||
c8c55782ec | |||
a1b272bd40 | |||
ed68dbd4bd | |||
3f00505659 | |||
5a41d4a0b9 | |||
3fd5b124f3 | |||
17442819c4 | |||
7adc629292 | |||
39640139fa | |||
0812c9e371 | |||
f111f54606 | |||
7e17851131 | |||
b674ae5b15 | |||
412c3f313c | |||
1838674cab | |||
30d9d470cd | |||
3236131377 | |||
9aaa8a94f1 | |||
2d43a7d875 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ memory.sqlite3
|
|||||||
/video
|
/video
|
||||||
/voice
|
/voice
|
||||||
/.idea
|
/.idea
|
||||||
|
Cargo.lock
|
2064
Cargo.lock
generated
2064
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
74
Cargo.toml
74
Cargo.toml
@ -1,34 +1,40 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "desubot"
|
name = "desubot"
|
||||||
version = "0.1.0"
|
version = "0.5.0"
|
||||||
authors = ["AB <ab@hexor.ru>"]
|
authors = ["AB <ab@hexor.ru>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bytes = "0.5"
|
bytes = "0.5"
|
||||||
tokio = { version = "0.2", features = ["full"]}
|
tokio = { version = "0.2", features = ["full"]}
|
||||||
|
tracing = "0.1.9"
|
||||||
tracing = "0.1.9"
|
tracing-futures = "0.2"
|
||||||
tracing-futures = "0.2"
|
multipart = { version = "0.16", default-features = false, features = ["client"] }
|
||||||
multipart = { version = "0.16", default-features = false, features = ["client"] }
|
telegram-bot = "0.8.0"
|
||||||
|
silicon = "0.4.0"
|
||||||
telegram-bot = "0.8.0"
|
hyper = "0.13"
|
||||||
|
hyper-tls = { version = "0.4", optional = true }
|
||||||
hyper = "0.13"
|
futures = "0.3"
|
||||||
hyper-tls = { version = "0.4", optional = true }
|
hyper-rustls = { version = "0.19", optional = true }
|
||||||
futures = "0.3"
|
rusqlite = { version = "0.24.2", features = ["bundled"]}
|
||||||
hyper-rustls = { version = "0.19", optional = true }
|
html-escape = "0.2"
|
||||||
|
regex = "1"
|
||||||
rusqlite = { version = "0.24.1", features = ["bundled"]}
|
reqwest = "0.10.9"
|
||||||
html-escape = "0.2"
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
reqwest = "0.10.9"
|
sha1 = "0.6.0"
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
env_logger = "0.7"
|
||||||
sha1 = "*"
|
log = { version = "^0.4.5", features = ["std"] }
|
||||||
env_logger = "0.7"
|
subprocess = "0.2.6"
|
||||||
log = { version = "^0.4.5", features = ["std"] }
|
serde_json = "1.0"
|
||||||
subprocess = "0.2.6"
|
markov = "1.1.0"
|
||||||
serde_json = "1.0"
|
rand = "0.7.3"
|
||||||
markov = "1.1.0"
|
mystem = "0.2.1"
|
||||||
rand = "0.7.3"
|
async-trait = "0.1.42"
|
||||||
|
sqlparser = "0.7.0"
|
||||||
|
|
||||||
|
[dependencies.syntect]
|
||||||
|
version = "4.4"
|
||||||
|
default-features = false
|
||||||
|
features = ["parsing", "dump-load", "regex-onig"]
|
7
README
7
README
@ -9,7 +9,8 @@ Telegram bot with light group statistic and heavy spy features.
|
|||||||
* Generate sentences using Markov Chains trained on history with /markov_all.
|
* Generate sentences using Markov Chains trained on history with /markov_all.
|
||||||
|
|
||||||
== TODO ==
|
== TODO ==
|
||||||
* Syntax highlighting for code exported to image.
|
* Syntax highlighting for CODE exported to image.
|
||||||
|
|
||||||
== Notes ==
|
== Important ==
|
||||||
* Desubot uses MyStem by Yandex for word stemming and assume that mystem binary is available in PATH. On Windows it may be placed on working directory. Both Linux and Windows mystem binary is in repo.
|
* Desubot uses MyStem by Yandex for word stemming and assume that mystem binary is available in PATH.
|
||||||
|
On Windows it may be placed on working directory. Both Linux and Windows mystem binary is in repo.
|
3
assets/README.md
Normal file
3
assets/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Assets
|
||||||
|
|
||||||
|
Silicon uses [bat](https://github.com/sharkdp/bat/tree/master/assets)'s syntax and theme resources.
|
BIN
assets/fonts/Hack-Bold.ttf
Normal file
BIN
assets/fonts/Hack-Bold.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Hack-BoldItalic.ttf
Normal file
BIN
assets/fonts/Hack-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Hack-Italic.ttf
Normal file
BIN
assets/fonts/Hack-Italic.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Hack-Regular.ttf
Normal file
BIN
assets/fonts/Hack-Regular.ttf
Normal file
Binary file not shown.
36
assets/help_text.rs
Normal file
36
assets/help_text.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
static CODE: &str = "<b>Code highlighter</b>
|
||||||
|
|
||||||
|
<i>Usage</i>
|
||||||
|
<pre>/CODE
|
||||||
|
#<theme - Dracula by default>
|
||||||
|
<CODE>
|
||||||
|
#<lang - JS by default></pre>
|
||||||
|
|
||||||
|
Language may be defined by both name and extension - Rust, rs...
|
||||||
|
Max lines - 80
|
||||||
|
|
||||||
|
List of themes:
|
||||||
|
1337
|
||||||
|
DarkNeon
|
||||||
|
Dracula
|
||||||
|
GitHub
|
||||||
|
Monokai_Extended
|
||||||
|
Monokai_Extended_Bright
|
||||||
|
Monokai_Extended_Light
|
||||||
|
Monokai_Extended_Origin
|
||||||
|
Nord
|
||||||
|
OneHalfDark
|
||||||
|
OneHalfLight
|
||||||
|
Solarized_(dark)
|
||||||
|
Solarized_(light)
|
||||||
|
Sublime_Snazzy
|
||||||
|
TwoDark
|
||||||
|
ansi-dark
|
||||||
|
ansi-light
|
||||||
|
base16
|
||||||
|
base16-256
|
||||||
|
gruvbox
|
||||||
|
gruvbox-light
|
||||||
|
gruvbox-white
|
||||||
|
zenburn
|
||||||
|
";
|
21
assets/sync_from_bat.py
Normal file
21
assets/sync_from_bat.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# Sync themes and syntaxes from [bat](https://github.com/sharkdp/bat/tree/master/assets)
|
||||||
|
|
||||||
|
import os
|
||||||
|
from glob import glob
|
||||||
|
from shutil import copy
|
||||||
|
|
||||||
|
if not os.path.exists('../../bat'):
|
||||||
|
os.system('git clone https://github.com/sharkdp/bat ../../bat')
|
||||||
|
else:
|
||||||
|
os.system('git -C ../../bat pull')
|
||||||
|
|
||||||
|
for syntax_file in glob('../../bat/assets/syntaxes/**/*.sublime-syntax'):
|
||||||
|
copy(syntax_file, './syntaxes/')
|
||||||
|
|
||||||
|
for theme_file in glob('../../bat/assets/themes/**/*.tmTheme'):
|
||||||
|
copy(theme_file, './themes/')
|
||||||
|
|
||||||
|
os.system('bat cache --build --source . --target .')
|
||||||
|
|
||||||
|
print('Finished.')
|
BIN
assets/syntaxes.bin
Normal file
BIN
assets/syntaxes.bin
Normal file
Binary file not shown.
4
assets/syntaxes/.gitignore
vendored
Normal file
4
assets/syntaxes/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
BIN
assets/themes.bin
Normal file
BIN
assets/themes.bin
Normal file
Binary file not shown.
5
assets/themes/.gitignore
vendored
Normal file
5
assets/themes/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Ignore everything in this directory
|
||||||
|
*
|
||||||
|
# Except this file
|
||||||
|
!.gitignore
|
||||||
|
!Dracula.tmTheme
|
940
assets/themes/Dracula.tmTheme
Normal file
940
assets/themes/Dracula.tmTheme
Normal file
@ -0,0 +1,940 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<!-- Dracula Theme v1.4.3
|
||||||
|
#
|
||||||
|
# https://github.com/dracula/sublime
|
||||||
|
#
|
||||||
|
# Copyright 2013-present, All rights reserved
|
||||||
|
#
|
||||||
|
# Code licensed under the MIT license
|
||||||
|
#
|
||||||
|
# @author Zeno Rocha <hi@zenorocha.com>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Dracula</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#282a36</string>
|
||||||
|
<key>caret</key>
|
||||||
|
<string>#f8f8f0</string>
|
||||||
|
<key>block_caret</key>
|
||||||
|
<string>#999a9e</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#f8f8f2</string>
|
||||||
|
<key>invisibles</key>
|
||||||
|
<string>#3B3A32</string>
|
||||||
|
<key>lineHighlight</key>
|
||||||
|
<string>#44475a</string>
|
||||||
|
<key>selection</key>
|
||||||
|
<string>#44475a</string>
|
||||||
|
<key>findHighlight</key>
|
||||||
|
<string>#effb7b</string>
|
||||||
|
<key>findHighlightForeground</key>
|
||||||
|
<string>#000000</string>
|
||||||
|
<key>selectionBorder</key>
|
||||||
|
<string>#222218</string>
|
||||||
|
<key>activeGuide</key>
|
||||||
|
<string>#9D550FB0</string>
|
||||||
|
<key>bracketsForeground</key>
|
||||||
|
<string>#F8F8F2A5</string>
|
||||||
|
<key>bracketsOptions</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>bracketContentsForeground</key>
|
||||||
|
<string>#F8F8F2A5</string>
|
||||||
|
<key>bracketContentsOptions</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>tagsOptions</key>
|
||||||
|
<string>stippled_underline</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Comment</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>comment</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272a4</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>String</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#f1fa8c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Number</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.numeric</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Built-in constant</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.language</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>User-defined constant</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.character, constant.other</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Ruby's @variable</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.other.readwrite.instance</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffb86c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>String interpolation</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.character.escaped, constant.character.escape, string source, string source.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Ruby Regexp</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>source.ruby string.regexp.classic.ruby,source.ruby string.regexp.mod-r.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff5555</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Keyword</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>keyword</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage.type</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage Type Namespace</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage.type.namespace</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage Type Class</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage.type.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Class name</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Meta Path</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.path</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#66d9ef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Inherited class</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.inherited-class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic underline</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function name</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.function</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Function argument</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.parameter</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffb86c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Tag name</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.tag</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Tag attribute</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.other.attribute-name</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Library function</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.function</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Library constant</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.constant</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6be5fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Library class/type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.type, support.class</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#66d9ef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Library variable</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.other.variable</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Support Other Namespace</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.other.namespace</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#66d9ef</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Invalid</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string></string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F8F8F0</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Invalid deprecated</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>invalid.deprecated</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F8F8F0</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON String</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.structure.dictionary.json string.quoted.double.json</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#CFCFC2</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>diff.header</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.diff, meta.diff.header</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272a4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>diff.deleted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.deleted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>diff.inserted</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.inserted</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>diff.changed</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.changed</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#E6DB74</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>constant.numeric.line-number.find-in-files - match</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.filename</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#E6DB74</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>message.error</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F83333</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON Punctuation</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.definition.string.begin.json - meta.structure.dictionary.value.json, punctuation.definition.string.end.json - meta.structure.dictionary.value.json</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#EEEEEE</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON Structure</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.structure.dictionary.json string.quoted.double.json</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON String</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.structure.dictionary.value.json string.quoted.double.json</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#f1fa8c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 6 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta meta meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 5 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffb86c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 4 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 3 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 2 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>JSON: 1 deep</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta meta.structure.dictionary.value string</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffb86c</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
|
||||||
|
<!-- Markdown Tweaks -->
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: strike</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.strike</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FFB86C</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: bold</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.bold</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>bold</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FFB86C</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: italic</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.italic</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FFB86C</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: heading</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.heading</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8BE9FD</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: List Items Punctuation</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.definition.list_item.markdown</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FF79C6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Blockquote</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.quote</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Blockquote Punctuation</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.definition.blockquote.markdown</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>background</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Separator</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.separator</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: raw inline</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>text.html.markdown markup.raw.inline</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50FA7B</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: underline</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.underline</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>underline</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#BD93F9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markup: Raw block</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.raw.block</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#CFCFC2</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Raw Block fenced source</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>markup.raw.block.fenced.markdown source</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#F8F8F2</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Fenced Bode Block</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.definition.fenced.markdown, variable.language.fenced.markdown</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Markdown: Fenced Language</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.language.fenced.markdown</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>fontStyle</key>
|
||||||
|
<string>italic</string>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#6272A4</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Accessor</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.accessor</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FF79C6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Meta Function Return Type</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>meta.function.return-type</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#FF79C6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Section Block Begin</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.section.block.begin</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Section Block End</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.section.block.end</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Section Embedded Begin</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.section.embedded.begin</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Section Embedded End</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.section.embedded.end</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Punctuation Separator Namespace</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>punctuation.separator.namespace</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable Function</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.function</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#50fa7b</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable Other</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.other</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Variable Language</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>variable.language</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Entity Name Module Ruby</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.module.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Entity Name Constant Ruby</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.constant.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#bd93f9</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Support Function Builtin Ruby</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>support.function.builtin.ruby</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ffffff</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Storage Type Namespace CS</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>storage.type.namespace.cs</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#ff79c6</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>name</key>
|
||||||
|
<string>Entity Name Namespace CS</string>
|
||||||
|
<key>scope</key>
|
||||||
|
<string>entity.name.namespace.cs</string>
|
||||||
|
<key>settings</key>
|
||||||
|
<dict>
|
||||||
|
<key>foreground</key>
|
||||||
|
<string>#8be9fd</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>uuid</key>
|
||||||
|
<string>83091B89-765E-4F0D-9275-0EC6CB084126</string>
|
||||||
|
<key>colorSpaceName</key>
|
||||||
|
<string>sRGB</string>
|
||||||
|
<key>semanticClass</key>
|
||||||
|
<string>theme.dracula</string>
|
||||||
|
<key>author</key>
|
||||||
|
<string>Zeno Rocha</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
690
src/commands.rs
690
src/commands.rs
@ -1,103 +1,635 @@
|
|||||||
|
#![allow(unused_variables)]
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::errors::Error;
|
use crate::errors::Error;
|
||||||
|
use crate::errors::Error::{CodeHighlightningError, SQLITE3Error, SQLInvalidCommand};
|
||||||
|
use async_trait::async_trait;
|
||||||
use html_escape::encode_text;
|
use html_escape::encode_text;
|
||||||
use markov::Chain;
|
use markov::Chain;
|
||||||
|
use mystem::Case::Nominative;
|
||||||
|
use mystem::Gender::Feminine;
|
||||||
|
use mystem::MyStem;
|
||||||
|
use mystem::Person::First;
|
||||||
|
use mystem::Tense::{Inpresent, Past};
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
use regex::Regex;
|
||||||
|
use sqlparser::ast::Statement;
|
||||||
|
use sqlparser::dialect::GenericDialect;
|
||||||
|
use sqlparser::parser::Parser;
|
||||||
|
use syntect::easy::HighlightLines;
|
||||||
|
use syntect::parsing::SyntaxReference;
|
||||||
|
use syntect::util::LinesWithEndings;
|
||||||
use telegram_bot::prelude::*;
|
use telegram_bot::prelude::*;
|
||||||
use telegram_bot::{Api, Message, ParseMode};
|
use telegram_bot::{Api, Message, ParseMode};
|
||||||
|
use syntect::highlighting::Theme;
|
||||||
|
|
||||||
pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> {
|
pub struct Here {
|
||||||
let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap();
|
pub data: String,
|
||||||
for u in &members {
|
}
|
||||||
debug!("Found user {:?} in chat {}", u, message.chat.id());
|
pub struct Top {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
pub struct MarkovAll {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
pub struct Markov {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
pub struct Omedeto {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
pub struct Sql {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
pub struct Code {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait Execute {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error>;
|
||||||
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error>;
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Execute for Sql {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
}
|
}
|
||||||
let mut msg = "<b>I summon you</b>, ".to_string();
|
|
||||||
for user in members {
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
let mention = match user.username {
|
let mut sql = self.data.clone();
|
||||||
Some(username) => format!("@{}", username),
|
let is_head = if sql.starts_with('-') {
|
||||||
_ => format!(
|
sql = sql.replacen("-", "", 1);
|
||||||
"<a href=\"tg://user?id={}\">{}</a>",
|
false
|
||||||
encode_text(&user.id.to_string()),
|
} else {
|
||||||
encode_text(&user.first_name)
|
true
|
||||||
),
|
|
||||||
};
|
};
|
||||||
msg = format!("{} {}", msg, mention);
|
let dialect = GenericDialect {};
|
||||||
|
let ast: Vec<Statement> = match Parser::parse_sql(&dialect, &sql) {
|
||||||
|
Ok(ast) => ast,
|
||||||
|
Err(_) => {
|
||||||
|
warn!("Invalid SQL - {}", sql);
|
||||||
|
return Err(SQLInvalidCommand);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match ast.len() {
|
||||||
|
l if l > 1 => {
|
||||||
|
return Err(Error::SQLBannedCommand(
|
||||||
|
"🚫 One statement per message allowed 🚫".into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
match ast[0] {
|
||||||
|
sqlparser::ast::Statement::Query { .. } => {}
|
||||||
|
_ => {
|
||||||
|
return Err(Error::SQLBannedCommand(
|
||||||
|
"🚫 SELECT requests allowed only 🚫".into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let conn = db::open()?;
|
||||||
|
let mut stmt = conn.prepare_cached(&sql)?;
|
||||||
|
|
||||||
|
let mut rows = match stmt.query(rusqlite::NO_PARAMS) {
|
||||||
|
Err(e) => return Err(SQLITE3Error(e)),
|
||||||
|
Ok(rows) => rows,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut res: Vec<Vec<String>> = match rows.column_names() {
|
||||||
|
Some(n) => vec![n
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| {
|
||||||
|
let t = String::from(s);
|
||||||
|
if t.len() > 10 {
|
||||||
|
"EMSGSIZE".to_string()
|
||||||
|
} else {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()],
|
||||||
|
None => return Err(SQLInvalidCommand),
|
||||||
|
};
|
||||||
|
|
||||||
|
let index_count = match rows.column_count() {
|
||||||
|
Some(c) => c,
|
||||||
|
None => return Err(SQLInvalidCommand),
|
||||||
|
};
|
||||||
|
while let Some(row) = rows.next().unwrap() {
|
||||||
|
let mut tmp: Vec<String> = Vec::new();
|
||||||
|
for i in 0..index_count {
|
||||||
|
match row.get(i).unwrap_or(None) {
|
||||||
|
Some(rusqlite::types::Value::Text(t)) => tmp.push(t),
|
||||||
|
Some(rusqlite::types::Value::Integer(t)) => tmp.push(t.to_string()),
|
||||||
|
Some(rusqlite::types::Value::Blob(_)) => tmp.push("Binary".to_string()),
|
||||||
|
Some(rusqlite::types::Value::Real(t)) => tmp.push(t.to_string()),
|
||||||
|
Some(rusqlite::types::Value::Null) => tmp.push("Null".to_string()),
|
||||||
|
None => tmp.push("Null".to_string()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
res.push(tmp);
|
||||||
|
}
|
||||||
|
if res.len() > 100 {
|
||||||
|
return Err(Error::SQLResultTooLong(
|
||||||
|
"SQL result too long. Lines limit is 100. Use LIMIT".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// add Header
|
||||||
|
let mut msg = if is_head {
|
||||||
|
let mut x = String::from("<b>");
|
||||||
|
for head in res[0].iter() {
|
||||||
|
x = format!("{} {}", x, head);
|
||||||
|
}
|
||||||
|
format!("{}{}", x, "</b>\n")
|
||||||
|
} else {
|
||||||
|
String::new()
|
||||||
|
};
|
||||||
|
|
||||||
|
// remove header
|
||||||
|
res.remove(0);
|
||||||
|
|
||||||
|
msg = format!("{}{}", msg, "<pre>");
|
||||||
|
for line in res.iter() {
|
||||||
|
for field in line.iter() {
|
||||||
|
msg = format!("{}{}", msg, format!("{} ", field));
|
||||||
|
}
|
||||||
|
msg = format!("{}{}", msg, "\n");
|
||||||
|
}
|
||||||
|
msg = format!("{}{}", msg, "</pre>");
|
||||||
|
msg = if msg.len() > 4096 {
|
||||||
|
"🚫 Result is too big. Use LIMIT 🚫".into()
|
||||||
|
} else {
|
||||||
|
msg
|
||||||
|
};
|
||||||
|
Ok(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
match api
|
#[allow(unused_variables)]
|
||||||
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
async fn exec_mystem(
|
||||||
.await
|
&self,
|
||||||
{
|
api: &Api,
|
||||||
Ok(_) => debug!("/here command sent to {}", message.chat.id()),
|
message: &Message,
|
||||||
Err(_) => warn!("/here command sent failed to {}", message.chat.id()),
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
}
|
}
|
||||||
//api.send(message.chat.text("Text to message chat")).await?;
|
|
||||||
//api.send(message.from.text("Private text")).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn top(api: Api, message: Message) -> Result<(), Error> {
|
#[async_trait]
|
||||||
let top = db::get_top(&message).await?;
|
impl Execute for Here {
|
||||||
let mut msg = "<b>Your top using words:</b>\n<pre>".to_string();
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
let mut counter = 1;
|
let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap();
|
||||||
for word in top.iter() {
|
for u in &members {
|
||||||
msg = format!(
|
debug!("Found user {:?} in chat {}", u, message.chat.id());
|
||||||
"{} <b>{}</b> {} - {}\n",
|
}
|
||||||
msg, counter, word.word, word.count
|
let mut msg = "<b>I summon you</b>, ".to_string();
|
||||||
|
for user in members {
|
||||||
|
let mention = match user.username {
|
||||||
|
Some(username) => format!("@{}", username),
|
||||||
|
_ => format!(
|
||||||
|
"<a href=\"tg://user?id={}\">{}</a>",
|
||||||
|
encode_text(&user.id.to_string()),
|
||||||
|
encode_text(&user.first_name)
|
||||||
|
),
|
||||||
|
};
|
||||||
|
msg = format!("{} {}", msg, mention);
|
||||||
|
}
|
||||||
|
|
||||||
|
match api
|
||||||
|
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => debug!("/here command sent to {}", message.chat.id()),
|
||||||
|
Err(_) => warn!("/here command sent failed to {}", message.chat.id()),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Execute for Top {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
let top = db::get_top(&message).await?;
|
||||||
|
let mut msg = "<b>Your top using words:</b>\n<pre>".to_string();
|
||||||
|
let mut counter = 1;
|
||||||
|
for word in top.iter() {
|
||||||
|
msg = format!(
|
||||||
|
"{} <b>{}</b> {} - {}\n",
|
||||||
|
msg, counter, word.word, word.count
|
||||||
|
);
|
||||||
|
counter += 1;
|
||||||
|
}
|
||||||
|
msg = format!("{}{}", msg, "</pre>");
|
||||||
|
match api
|
||||||
|
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => debug!("/top command sent to {}", message.chat.id()),
|
||||||
|
Err(_) => warn!("/top command sent failed to {}", message.chat.id()),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Execute for MarkovAll {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
let messages = db::get_messages_random_all().await?;
|
||||||
|
let mut chain = Chain::new();
|
||||||
|
chain.feed(messages);
|
||||||
|
let mut sentences = chain.generate();
|
||||||
|
let mut msg = String::new();
|
||||||
|
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
||||||
|
msg = format!("{} {}", msg, sentences.pop().unwrap());
|
||||||
|
}
|
||||||
|
match api
|
||||||
|
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => debug!("/markov_all command sent to {}", message.chat.id()),
|
||||||
|
Err(_) => warn!("/markov_all command sent failed to {}", message.chat.id()),
|
||||||
|
}
|
||||||
|
//api.send(message.chat.text("Text to message chat")).await?;
|
||||||
|
//api.send(message.from.text("Private text")).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Execute for Markov {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
let messages = db::get_messages_random_group(&message).await?;
|
||||||
|
let mut chain = Chain::new();
|
||||||
|
chain.feed(messages);
|
||||||
|
let mut sentences = chain.generate();
|
||||||
|
let mut msg = String::new();
|
||||||
|
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
||||||
|
msg = format!("{} {}", msg, sentences.pop().unwrap());
|
||||||
|
}
|
||||||
|
match api
|
||||||
|
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => debug!("/markov command sent to {}", message.chat.id()),
|
||||||
|
Err(_) => warn!("/markov command sent failed to {}", message.chat.id()),
|
||||||
|
}
|
||||||
|
//api.send(message.chat.text("Text to message chat")).await?;
|
||||||
|
//api.send(message.from.text("Private text")).await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Execute for Omedeto {
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[warn(unused_must_use)]
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let all_msg = db::get_messages_user_all(&message).await?;
|
||||||
|
let re = Regex::new(r"^[яЯ] [а-яА-Я]+(-[а-яА-Я]+(_[а-яА-Я]+)*)*").unwrap();
|
||||||
|
let mut nouns: Vec<String> = all_msg
|
||||||
|
.iter()
|
||||||
|
.filter(|m| re.is_match(m))
|
||||||
|
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||||
|
.filter(|m| {
|
||||||
|
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||||
|
if !stem.is_empty() {
|
||||||
|
if !stem[0].lex.is_empty() {
|
||||||
|
match stem[0].lex[0].grammem.part_of_speech {
|
||||||
|
mystem::PartOfSpeech::Noun => stem[0].lex[0]
|
||||||
|
.grammem
|
||||||
|
.facts
|
||||||
|
.contains(&mystem::Fact::Case(Nominative)),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
|
||||||
|
.collect();
|
||||||
|
nouns.sort();
|
||||||
|
nouns.dedup();
|
||||||
|
nouns.shuffle(&mut rand::thread_rng());
|
||||||
|
//debug!("Found {} nouns. {:#?}", nouns.len(), nouns);
|
||||||
|
|
||||||
|
let mut verbs_p: Vec<String> = all_msg
|
||||||
|
.iter()
|
||||||
|
.filter(|m| re.is_match(m))
|
||||||
|
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||||
|
.filter(|m| {
|
||||||
|
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||||
|
#[allow(clippy::if_same_then_else)]
|
||||||
|
if stem.is_empty() {
|
||||||
|
false
|
||||||
|
} else if stem[0].lex.is_empty() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
match stem[0].lex[0].grammem.part_of_speech {
|
||||||
|
mystem::PartOfSpeech::Verb => stem[0].lex[0]
|
||||||
|
.grammem
|
||||||
|
.facts
|
||||||
|
.contains(&mystem::Fact::Tense(Past)),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
|
||||||
|
.collect();
|
||||||
|
verbs_p.sort();
|
||||||
|
verbs_p.dedup();
|
||||||
|
verbs_p.shuffle(&mut rand::thread_rng());
|
||||||
|
//debug!("Found {} past verbs. {:#?}", verbs_p.len(), verbs_p);
|
||||||
|
|
||||||
|
let mut verbs_i: Vec<String> = all_msg
|
||||||
|
.iter()
|
||||||
|
.filter(|m| re.is_match(m))
|
||||||
|
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||||
|
.filter(|m| {
|
||||||
|
let stem = mystem.stemming(m.clone()).unwrap_or_default();
|
||||||
|
#[allow(clippy::if_same_then_else)]
|
||||||
|
if stem.is_empty() {
|
||||||
|
false
|
||||||
|
} else if stem[0].lex.is_empty() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
match stem[0].lex[0].grammem.part_of_speech {
|
||||||
|
mystem::PartOfSpeech::Verb => {
|
||||||
|
stem[0].lex[0]
|
||||||
|
.grammem
|
||||||
|
.facts
|
||||||
|
.contains(&mystem::Fact::Tense(Inpresent))
|
||||||
|
&& stem[0].lex[0]
|
||||||
|
.grammem
|
||||||
|
.facts
|
||||||
|
.contains(&mystem::Fact::Person(First))
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map(|w| w.replace(|z| z == '.' || z == ',', ""))
|
||||||
|
.collect();
|
||||||
|
verbs_i.sort();
|
||||||
|
verbs_i.dedup();
|
||||||
|
verbs_i.shuffle(&mut rand::thread_rng());
|
||||||
|
//debug!("Found {} inpresent verbs. {:#?}", verbs_i.len(), verbs_i);
|
||||||
|
|
||||||
|
if nouns.is_empty() {
|
||||||
|
nouns.push(message.from.first_name.to_string());
|
||||||
|
}
|
||||||
|
let start: Vec<String> = vec![
|
||||||
|
"С новым годом".into(),
|
||||||
|
"С НГ тебя".into(),
|
||||||
|
"Поздравляю".into(),
|
||||||
|
"Поздравляю с НГ".into(),
|
||||||
|
];
|
||||||
|
let placeholders: Vec<String> = vec![
|
||||||
|
"[ДАННЫЕ УДАЛЕНЫ]".into(),
|
||||||
|
"[СЕКРЕТНО]".into(),
|
||||||
|
"[НЕТ ДАННЫХ]".into(),
|
||||||
|
"[ОШИБКА ДОСТУПА]".into(),
|
||||||
|
];
|
||||||
|
//debug!("Nouns: {:#?}", nouns);
|
||||||
|
//debug!("Verbs: {:#?}", verbs);
|
||||||
|
|
||||||
|
let fem = {
|
||||||
|
let mut fm = 0;
|
||||||
|
let mut mu = 0;
|
||||||
|
all_msg
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|m| re.is_match(m))
|
||||||
|
.map(|m| m.split(' ').map(|s| s.to_string()).collect::<Vec<String>>()[1].clone())
|
||||||
|
.map(|m| {
|
||||||
|
let stem = mystem.stemming(m).unwrap_or_default();
|
||||||
|
#[allow(clippy::if_same_then_else)]
|
||||||
|
if stem.is_empty() {
|
||||||
|
} else if stem[0].lex.is_empty() {
|
||||||
|
} else {
|
||||||
|
if let mystem::PartOfSpeech::Verb = stem[0].lex[0].grammem.part_of_speech {
|
||||||
|
match stem[0].lex[0]
|
||||||
|
.grammem
|
||||||
|
.facts
|
||||||
|
.contains(&mystem::Fact::Tense(Past))
|
||||||
|
{
|
||||||
|
true => {
|
||||||
|
if stem[0].lex[0]
|
||||||
|
.grammem
|
||||||
|
.facts
|
||||||
|
.contains(&mystem::Fact::Gender(Feminine))
|
||||||
|
{
|
||||||
|
fm += 1;
|
||||||
|
} else {
|
||||||
|
mu += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.for_each(drop);
|
||||||
|
//debug!("fm - {}, mu - {}", fm, mu);
|
||||||
|
fm >= mu
|
||||||
|
};
|
||||||
|
//debug!("Is Feminine - {}", fem);
|
||||||
|
let result = format!(
|
||||||
|
"{} {} известн{} как {}, {}, а так же конечно {}. В прошедшем году ты часто давал{} нам знать, что ты {}, {} и {}. Нередко ты говорил{} я {}, я {} или даже я {}. =*",
|
||||||
|
start.choose(&mut rand::thread_rng()).unwrap(),
|
||||||
|
message.from.first_name.to_string(),
|
||||||
|
{ if fem { "ая" } else { "ый" } },
|
||||||
|
nouns.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
|
nouns.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
|
nouns.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
|
{ if fem { "а" } else { "" } },
|
||||||
|
verbs_p.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
|
verbs_p.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
|
verbs_p.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
|
{ if fem { "а" } else { "" } },
|
||||||
|
verbs_i.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
|
verbs_i.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
|
verbs_i.pop().unwrap_or_else(|| placeholders.choose(&mut rand::thread_rng()).unwrap().to_string()),
|
||||||
);
|
);
|
||||||
counter += 1;
|
match api
|
||||||
|
.send(
|
||||||
|
message
|
||||||
|
.text_reply(result.trim())
|
||||||
|
.parse_mode(ParseMode::Html),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => debug!("/omedeto command sent to {}", message.chat.id()),
|
||||||
|
Err(_) => warn!("/omedeto command sent failed to {}", message.chat.id()),
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
msg = format!("{}{}", msg, "</pre>");
|
|
||||||
match api
|
|
||||||
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(_) => debug!("/top command sent to {}", message.chat.id()),
|
|
||||||
Err(_) => warn!("/top command sent failed to {}", message.chat.id()),
|
|
||||||
}
|
|
||||||
//api.send(message.chat.text("Text to message chat")).await?;
|
|
||||||
//api.send(message.from.text("Private text")).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn markov_all(api: Api, message: Message) -> Result<(), Error> {
|
#[async_trait]
|
||||||
let messages = db::get_random_messages().await?;
|
impl Execute for Code {
|
||||||
let mut chain = Chain::new();
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
chain.feed(messages);
|
unimplemented!()
|
||||||
let mut sentences = chain.generate();
|
|
||||||
let mut msg = String::new();
|
|
||||||
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
|
||||||
msg = format!("{} {}", msg, sentences.pop().unwrap());
|
|
||||||
}
|
}
|
||||||
match api
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
let mut lines: Vec<String> = self.data.trim().split("\n").map(|s| s.to_string()).collect();
|
||||||
.await
|
if lines.len() >= 81 {
|
||||||
{
|
return Err(CodeHighlightningError);
|
||||||
Ok(_) => debug!("/markov_all command sent to {}", message.chat.id()),
|
}
|
||||||
Err(_) => warn!("/markov_all command sent failed to {}", message.chat.id()),
|
let last_line = &lines[lines.len()-1];
|
||||||
}
|
|
||||||
//api.send(message.chat.text("Text to message chat")).await?;
|
|
||||||
//api.send(message.from.text("Private text")).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn markov(api: Api, message: Message) -> Result<(), Error> {
|
let tags = last_line
|
||||||
let messages = db::get_random_messages_group(&message).await?;
|
.trim()
|
||||||
let mut chain = Chain::new();
|
.split(|s| s == ' ' || s == '\n')
|
||||||
chain.feed(messages);
|
.filter(|s| s.starts_with("#"))
|
||||||
let mut sentences = chain.generate();
|
.map(|s| s.to_string().replace("#", ""))
|
||||||
let mut msg = String::new();
|
.map(|s| s.to_string().replace("_", " "))
|
||||||
for _ in 1..rand::thread_rng().gen_range(2, 10) {
|
.collect::<Vec<_>>();
|
||||||
msg = format!("{} {}", msg, sentences.pop().unwrap());
|
|
||||||
|
let code = if tags.is_empty() {
|
||||||
|
self.data.trim().to_string()
|
||||||
|
} else {
|
||||||
|
let _ = lines.pop();
|
||||||
|
lines.join("\n")
|
||||||
|
};
|
||||||
|
if code.is_empty() {
|
||||||
|
return Err(CodeHighlightningError);
|
||||||
|
}
|
||||||
|
let (ps, ts) = silicon::utils::init_syntect();
|
||||||
|
let syntax: Vec<&SyntaxReference> = tags
|
||||||
|
.iter()
|
||||||
|
.map(|s| ps.find_syntax_by_token(s))
|
||||||
|
.filter(|s| s.is_some())
|
||||||
|
.map(|s| s.unwrap())
|
||||||
|
.collect();
|
||||||
|
let syntax = if syntax.len() != 1 {
|
||||||
|
ps.find_syntax_by_token("js").unwrap()
|
||||||
|
} else {
|
||||||
|
syntax[0]
|
||||||
|
};
|
||||||
|
let theme: Vec<&Theme> = tags
|
||||||
|
.iter()
|
||||||
|
.map(|s| ts.themes.get(s))
|
||||||
|
.filter(|s| s.is_some())
|
||||||
|
.map(|s| s.unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
|
||||||
|
let theme = if theme.len() != 1 {
|
||||||
|
ts.themes.get("Dracula").unwrap()
|
||||||
|
} else {
|
||||||
|
theme[0]
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut h = HighlightLines::new(syntax, theme);
|
||||||
|
let highlight = LinesWithEndings::from(&code)
|
||||||
|
.map(|line| h.highlight(line, &ps))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let formatter = silicon::formatter::ImageFormatterBuilder::<String>::new()
|
||||||
|
.window_controls(false)
|
||||||
|
.round_corner(false);
|
||||||
|
let mut formatter = formatter.build().unwrap();
|
||||||
|
let image = formatter.format(&highlight, &theme);
|
||||||
|
let path = "code.png";
|
||||||
|
image
|
||||||
|
.save(&path)
|
||||||
|
.map_err(|e| error!("Failed to save image to {}: {}", path, e))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// let file = InputFileUpload::with_path("CODE.png");
|
||||||
|
// api.send(message.chat.document(&file)).await?;
|
||||||
|
//
|
||||||
|
// // Send an image from disk
|
||||||
|
// api.send( message.chat.photo(&file)).await?;
|
||||||
|
//debug!("{:#?}", formatter);
|
||||||
|
Ok(path.into())
|
||||||
}
|
}
|
||||||
match api
|
|
||||||
.send(message.text_reply(msg.trim()).parse_mode(ParseMode::Html))
|
async fn exec_mystem(
|
||||||
.await
|
&self,
|
||||||
{
|
api: &Api,
|
||||||
Ok(_) => debug!("/markov command sent to {}", message.chat.id()),
|
message: &Message,
|
||||||
Err(_) => warn!("/markov command sent failed to {}", message.chat.id()),
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
}
|
}
|
||||||
//api.send(message.chat.text("Text to message chat")).await?;
|
|
||||||
//api.send(message.from.text("Private text")).await?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
89
src/db.rs
89
src/db.rs
@ -1,5 +1,4 @@
|
|||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::mystem;
|
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use rusqlite::{named_params, params, Connection, Error, Result};
|
use rusqlite::{named_params, params, Connection, Error, Result};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
@ -55,7 +54,7 @@ pub(crate) fn get_user(id: telegram_bot::UserId) -> Result<telegram_bot::User, e
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if users.len() == 0 {
|
if users.is_empty() {
|
||||||
Err(errors::Error::UserNotFound)
|
Err(errors::Error::UserNotFound)
|
||||||
} else {
|
} else {
|
||||||
Ok(users[0].clone())
|
Ok(users[0].clone())
|
||||||
@ -75,14 +74,14 @@ pub(crate) fn get_conf(id: telegram_bot::ChatId) -> Result<Conf, errors::Error>
|
|||||||
date: row.get(2)?,
|
date: row.get(2)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if confs.len() == 0 {
|
if confs.is_empty() {
|
||||||
Err(errors::Error::ConfNotFound)
|
Err(errors::Error::ConfNotFound)
|
||||||
} else {
|
} else {
|
||||||
Ok(confs[0].clone())
|
Ok(confs[0].clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
#[allow(dead_code)]
|
||||||
pub(crate) fn get_confs() -> Result<Vec<Conf>> {
|
pub(crate) fn get_confs() -> Result<Vec<Conf>> {
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
let mut stmt = conn.prepare("SELECT id, title, date FROM conf")?;
|
let mut stmt = conn.prepare("SELECT id, title, date FROM conf")?;
|
||||||
@ -101,8 +100,8 @@ pub(crate) fn get_confs() -> Result<Vec<Conf>> {
|
|||||||
|
|
||||||
Ok(confs)
|
Ok(confs)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
pub(crate) async fn get_random_messages() -> Result<Vec<String>, Error> {
|
pub(crate) async fn get_messages_random_all() -> Result<Vec<String>, Error> {
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
let mut stmt = conn.prepare_cached("SELECT text FROM messages ORDER BY RANDOM() LIMIT 50")?;
|
let mut stmt = conn.prepare_cached("SELECT text FROM messages ORDER BY RANDOM() LIMIT 50")?;
|
||||||
let mut rows = stmt.query_named(named_params![])?;
|
let mut rows = stmt.query_named(named_params![])?;
|
||||||
@ -114,17 +113,18 @@ pub(crate) async fn get_random_messages() -> Result<Vec<String>, Error> {
|
|||||||
Ok(messages)
|
Ok(messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_random_messages_group(
|
pub(crate) async fn get_messages_random_group(
|
||||||
message: &telegram_bot::Message
|
message: &telegram_bot::Message,
|
||||||
) -> Result<Vec<String>, Error> {
|
) -> Result<Vec<String>, Error> {
|
||||||
let conf_id = i64::from(message.chat.id());
|
let conf_id = i64::from(message.chat.id());
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
let mut stmt = conn.prepare_cached("
|
let mut stmt = conn.prepare_cached(
|
||||||
|
"
|
||||||
SELECT m.text FROM messages m
|
SELECT m.text FROM messages m
|
||||||
LEFT JOIN relations r ON r.msg_id = m.id
|
LEFT JOIN relations r ON r.msg_id = m.id
|
||||||
WHERE r.conf_id = :conf_id
|
WHERE r.conf_id = :conf_id
|
||||||
ORDER BY RANDOM() LIMIT 50
|
ORDER BY RANDOM() LIMIT 50
|
||||||
"
|
",
|
||||||
)?;
|
)?;
|
||||||
let mut rows = stmt.query_named(named_params! {":conf_id": conf_id})?;
|
let mut rows = stmt.query_named(named_params! {":conf_id": conf_id})?;
|
||||||
let mut messages = Vec::new();
|
let mut messages = Vec::new();
|
||||||
@ -135,6 +135,51 @@ pub(crate) async fn get_random_messages_group(
|
|||||||
Ok(messages)
|
Ok(messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) async fn get_messages_user_group(
|
||||||
|
message: &telegram_bot::Message,
|
||||||
|
) -> Result<Vec<String>, Error> {
|
||||||
|
let conf_id = i64::from(message.chat.id());
|
||||||
|
let user_id = i64::from(message.from.id);
|
||||||
|
let conn = open()?;
|
||||||
|
let mut stmt = conn.prepare_cached(
|
||||||
|
"
|
||||||
|
SELECT m.text FROM messages m
|
||||||
|
LEFT JOIN relations r ON r.msg_id = m.id
|
||||||
|
WHERE r.conf_id = :conf_id
|
||||||
|
AND r.user_id = :user_id
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
let mut rows = stmt.query_named(named_params! {":conf_id": conf_id, ":user_id": user_id})?;
|
||||||
|
let mut messages = Vec::new();
|
||||||
|
|
||||||
|
while let Some(row) = rows.next()? {
|
||||||
|
messages.push(row.get(0)?)
|
||||||
|
}
|
||||||
|
Ok(messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn get_messages_user_all(
|
||||||
|
message: &telegram_bot::Message,
|
||||||
|
) -> Result<Vec<String>, Error> {
|
||||||
|
let user_id = i64::from(message.from.id);
|
||||||
|
let conn = open()?;
|
||||||
|
let mut stmt = conn.prepare_cached(
|
||||||
|
"
|
||||||
|
SELECT m.text FROM messages m
|
||||||
|
LEFT JOIN relations r ON r.msg_id = m.id
|
||||||
|
WHERE r.user_id = :user_id
|
||||||
|
",
|
||||||
|
)?;
|
||||||
|
let mut rows = stmt.query_named(named_params! {":user_id": user_id})?;
|
||||||
|
let mut messages = Vec::new();
|
||||||
|
|
||||||
|
while let Some(row) = rows.next()? {
|
||||||
|
messages.push(row.get(0)?)
|
||||||
|
}
|
||||||
|
Ok(messages)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn get_members(id: telegram_bot::ChatId) -> Result<Vec<telegram_bot::User>> {
|
pub(crate) fn get_members(id: telegram_bot::ChatId) -> Result<Vec<telegram_bot::User>> {
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
let mut stmt = conn.prepare_cached(
|
let mut stmt = conn.prepare_cached(
|
||||||
@ -300,14 +345,12 @@ pub(crate) async fn get_file(file_id: String) -> Result<i64, errors::Error> {
|
|||||||
Ok(id) => Ok(id),
|
Ok(id) => Ok(id),
|
||||||
Err(_) => Err(errors::Error::FileNotFound),
|
Err(_) => Err(errors::Error::FileNotFound),
|
||||||
};
|
};
|
||||||
|
|
||||||
file_rowid
|
file_rowid
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_word(word: &String) -> Result<i64, errors::Error> {
|
async fn add_word(word: &str) -> Result<i64, errors::Error> {
|
||||||
match get_stop_word(&word).await {
|
if get_stop_word(&word).await.is_err() {
|
||||||
Err(_) => return Err(errors::Error::WordInStopList),
|
return Err(errors::Error::WordInStopList);
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
let word_rowid =
|
let word_rowid =
|
||||||
@ -321,7 +364,7 @@ async fn add_word(word: &String) -> Result<i64, errors::Error> {
|
|||||||
Ok(word_rowid)
|
Ok(word_rowid)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_stop_word(stop_word: &String) -> Result<(), errors::Error> {
|
async fn get_stop_word(stop_word: &str) -> Result<(), errors::Error> {
|
||||||
let conn = open()?;
|
let conn = open()?;
|
||||||
match conn.execute_named(
|
match conn.execute_named(
|
||||||
"SELECT rowid FROM stop_words WHERE word = (:stop_word)",
|
"SELECT rowid FROM stop_words WHERE word = (:stop_word)",
|
||||||
@ -355,6 +398,7 @@ async fn add_relation(word_id: i64, msg_id: i64, message: &Message) -> Result<i6
|
|||||||
Ok(rowid)
|
Ok(rowid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_must_use)]
|
||||||
pub(crate) async fn add_sentence(
|
pub(crate) async fn add_sentence(
|
||||||
message: &telegram_bot::Message,
|
message: &telegram_bot::Message,
|
||||||
mystem: &mut mystem::MyStem,
|
mystem: &mut mystem::MyStem,
|
||||||
@ -373,18 +417,21 @@ pub(crate) async fn add_sentence(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Save stemmed words
|
// Save stemmed words
|
||||||
let words = mystem.stemming(text).await?;
|
let words = mystem.stemming(text)?;
|
||||||
conn.execute("BEGIN TRANSACTION", params![]);
|
conn.execute("BEGIN TRANSACTION", params![]);
|
||||||
for word in words {
|
for word in words {
|
||||||
match add_word(&word).await {
|
if word.lex.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
match add_word(&word.lex[0].lex).await {
|
||||||
Ok(id) => {
|
Ok(id) => {
|
||||||
debug!("Added {}: rowid: {}", &word, id);
|
debug!("Added {}: rowid: {}", &word.lex[0].lex, id);
|
||||||
match add_relation(id, msg_rowid, message).await {
|
match add_relation(id, msg_rowid, message).await {
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => panic!("SQLITE3 Error: Relations failed: {:?}", e),
|
Err(e) => panic!("SQLITE3 Error: Relations failed: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(_) => debug!("Word {} is in stop list.", &word),
|
Err(_) => debug!("Word {} is in stop list.", &word.lex[0].lex),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conn.execute("END TRANSACTION", params![]);
|
conn.execute("END TRANSACTION", params![]);
|
||||||
@ -423,5 +470,3 @@ pub(crate) async fn get_top(
|
|||||||
}
|
}
|
||||||
Ok(top)
|
Ok(top)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use mystem::AppError as mystem_error;
|
||||||
use reqwest::Error as reqwest_error;
|
use reqwest::Error as reqwest_error;
|
||||||
use rusqlite::Error as sqlite_error;
|
use rusqlite::Error as sqlite_error;
|
||||||
use serde_json::Error as serde_error;
|
use serde_json::Error as serde_error;
|
||||||
@ -18,45 +19,84 @@ pub enum Error {
|
|||||||
FileNotFound,
|
FileNotFound,
|
||||||
JsonParseError(serde_error),
|
JsonParseError(serde_error),
|
||||||
PopenError(popen_error),
|
PopenError(popen_error),
|
||||||
|
MystemError(mystem_error),
|
||||||
|
SQLBannedCommand(String),
|
||||||
|
SQLInvalidCommand,
|
||||||
|
SQLResultTooLong(String),
|
||||||
|
CodeHighlightningError,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "An error occurred.")
|
write!(f, "An error occurred.")
|
||||||
|
// match self {
|
||||||
|
// _ => write!(f, "An error occurred."),
|
||||||
|
// // Error::UserNotFound => {}
|
||||||
|
// // Error::SQLITE3Error(_) => {}
|
||||||
|
// // Error::TelegramError(_) => {}
|
||||||
|
// // Error::ReqwestError(_) => {}
|
||||||
|
// // Error::ConfNotFound => {}
|
||||||
|
// // Error::WordNotFound => {}
|
||||||
|
// // Error::WordInStopList => {}
|
||||||
|
// // Error::IOError(_) => {}
|
||||||
|
// // Error::FileNotFound => {}
|
||||||
|
// // Error::JsonParseError(_) => {}
|
||||||
|
// // Error::PopenError(_) => {}
|
||||||
|
// // Error::MystemError(_) => {}
|
||||||
|
// // Error::SQLBannedCommand(_) => {}
|
||||||
|
// // Error::SQLInvalidCommand => {}
|
||||||
|
// // Error::SQLResultTooLong(_) => {}
|
||||||
|
// // Error::CodeHighlightningError(Help) => write!(f, "Code highlighter.\
|
||||||
|
// // <b>Usage</b><pre>/CODE\
|
||||||
|
// // #<theme>\
|
||||||
|
// // <CODE>\
|
||||||
|
// // #<lang></pre>\
|
||||||
|
// // \
|
||||||
|
// // List of themes:\
|
||||||
|
// // .")
|
||||||
|
// Error::CodeHighlightningError(help) => write!(f, "{}", help.description)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<sqlite_error> for Error {
|
impl From<sqlite_error> for Error {
|
||||||
fn from(e: sqlite_error) -> Error {
|
fn from(e: sqlite_error) -> Error {
|
||||||
return Error::SQLITE3Error(e);
|
Error::SQLITE3Error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<tg_error> for Error {
|
impl From<tg_error> for Error {
|
||||||
fn from(e: tg_error) -> Error {
|
fn from(e: tg_error) -> Error {
|
||||||
return Error::TelegramError(e);
|
Error::TelegramError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<reqwest_error> for Error {
|
impl From<reqwest_error> for Error {
|
||||||
fn from(e: reqwest_error) -> Error {
|
fn from(e: reqwest_error) -> Error {
|
||||||
return Error::ReqwestError(e);
|
Error::ReqwestError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io_error> for Error {
|
impl From<io_error> for Error {
|
||||||
fn from(e: io_error) -> Error {
|
fn from(e: io_error) -> Error {
|
||||||
return Error::IOError(e);
|
Error::IOError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<serde_error> for Error {
|
impl From<serde_error> for Error {
|
||||||
fn from(e: serde_error) -> Error {
|
fn from(e: serde_error) -> Error {
|
||||||
return Error::JsonParseError(e);
|
Error::JsonParseError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<popen_error> for Error {
|
impl From<popen_error> for Error {
|
||||||
fn from(e: popen_error) -> Error {
|
fn from(e: popen_error) -> Error {
|
||||||
return Error::PopenError(e);
|
Error::PopenError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<mystem_error> for Error {
|
||||||
|
fn from(e: mystem_error) -> Error {
|
||||||
|
Error::MystemError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
120
src/handlers.rs
120
src/handlers.rs
@ -1,11 +1,14 @@
|
|||||||
use telegram_bot::*;
|
//use crate::commands::Command;
|
||||||
use crate::mystem::MyStem;
|
use crate::commands::{Code, Execute, Here, Markov, MarkovAll, Omedeto, Sql, Top};
|
||||||
use crate::errors;
|
|
||||||
use crate::db;
|
use crate::db;
|
||||||
use crate::commands;
|
use crate::errors;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
use mystem::MyStem;
|
||||||
|
use telegram_bot::*;
|
||||||
|
|
||||||
|
|
||||||
|
include!("../assets/help_text.rs");
|
||||||
|
|
||||||
pub async fn handler(
|
pub async fn handler(
|
||||||
api: Api,
|
api: Api,
|
||||||
message: Message,
|
message: Message,
|
||||||
@ -13,7 +16,6 @@ pub async fn handler(
|
|||||||
mystem: &mut MyStem,
|
mystem: &mut MyStem,
|
||||||
me: User,
|
me: User,
|
||||||
) -> Result<(), errors::Error> {
|
) -> Result<(), errors::Error> {
|
||||||
|
|
||||||
match message.kind {
|
match message.kind {
|
||||||
MessageKind::Text { ref data, .. } => {
|
MessageKind::Text { ref data, .. } => {
|
||||||
let title = utils::get_title(&message);
|
let title = utils::get_title(&message);
|
||||||
@ -23,16 +25,102 @@ pub async fn handler(
|
|||||||
title,
|
title,
|
||||||
&message.from.id,
|
&message.from.id,
|
||||||
&message.from.first_name,
|
&message.from.first_name,
|
||||||
data
|
{if data.len() <= 200 {data} else {&data[..200]}}.replace("\n", " ")
|
||||||
);
|
);
|
||||||
db::add_sentence(&message, mystem).await?;
|
|
||||||
match data.as_str() {
|
let cleaned_message = data.replace(&format!("@{}", me.clone().username.unwrap()), "");
|
||||||
"/here" => commands::here(api, message).await?,
|
match cleaned_message.as_str() {
|
||||||
"/top" => commands::top(api, message).await?,
|
s if s.to_string().starts_with("/code") => {
|
||||||
"/stat" => commands::top(api, message).await?,
|
|
||||||
"/markov_all" => commands::markov_all(api, message).await?,
|
match {
|
||||||
"/markov" => commands::markov(api, message).await?,
|
Code {
|
||||||
_ => (),
|
data: s.replace("/code", ""),
|
||||||
|
}
|
||||||
|
.exec_with_result(&api, &message)
|
||||||
|
.await
|
||||||
|
} {
|
||||||
|
Ok(path) => {
|
||||||
|
let file = InputFileUpload::with_path(path.clone());
|
||||||
|
// api.send(message.chat.document(&file)).await?;
|
||||||
|
//
|
||||||
|
// // Send an image from disk
|
||||||
|
api.send(message.chat.photo(&file)).await?;
|
||||||
|
//debug!("{:#?}", formatter);
|
||||||
|
let _ = std::fs::remove_file(&path);
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
let _ = api
|
||||||
|
.send(message.text_reply(CODE).parse_mode(ParseMode::Html))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s if s.contains("/here") => {
|
||||||
|
db::add_sentence(&message, mystem).await?;
|
||||||
|
Here {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec(&api, &message)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
s if s.to_string().starts_with("/sql") => match {
|
||||||
|
Sql {
|
||||||
|
data: s.replace("/sql ", ""),
|
||||||
|
}
|
||||||
|
.exec_with_result(&api, &message)
|
||||||
|
.await
|
||||||
|
} {
|
||||||
|
Ok(msg) => {
|
||||||
|
let _ = api
|
||||||
|
.send(message.text_reply(msg).parse_mode(ParseMode::Html))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let _ = api
|
||||||
|
.send(
|
||||||
|
message
|
||||||
|
.text_reply(format!("Error: {:#?}", e))
|
||||||
|
.parse_mode(ParseMode::Html),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/top" => {
|
||||||
|
Top {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec(&api, &message)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
"/stat" => {
|
||||||
|
Top {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec(&api, &message)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
"/markov_all" => {
|
||||||
|
MarkovAll {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec(&api, &message)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
"/markov" => {
|
||||||
|
Markov {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec(&api, &message)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
"/omedeto" => {
|
||||||
|
Omedeto {
|
||||||
|
data: "".to_string(),
|
||||||
|
}
|
||||||
|
.exec_mystem(&api, &message, mystem)
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
_ => db::add_sentence(&message, mystem).await?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MessageKind::Photo { ref caption, .. } => {
|
MessageKind::Photo { ref caption, .. } => {
|
||||||
@ -43,7 +131,7 @@ pub async fn handler(
|
|||||||
title,
|
title,
|
||||||
&message.from.id,
|
&message.from.id,
|
||||||
&message.from.first_name,
|
&message.from.first_name,
|
||||||
caption.clone().unwrap_or("NO_TITLE".to_string())
|
caption.clone().unwrap_or_else(|| "NO_TITLE".to_string())
|
||||||
);
|
);
|
||||||
utils::get_files(api, message, token).await?;
|
utils::get_files(api, message, token).await?;
|
||||||
}
|
}
|
||||||
@ -56,7 +144,7 @@ pub async fn handler(
|
|||||||
title,
|
title,
|
||||||
&message.from.id,
|
&message.from.id,
|
||||||
&message.from.first_name,
|
&message.from.first_name,
|
||||||
caption.clone().unwrap_or("NO_TITLE".to_string())
|
caption.clone().unwrap_or_else(|| "NO_TITLE".to_string())
|
||||||
);
|
);
|
||||||
utils::get_files(api, message, token).await?;
|
utils::get_files(api, message, token).await?;
|
||||||
}
|
}
|
||||||
|
17
src/main.rs
17
src/main.rs
@ -9,9 +9,8 @@ use env_logger::Env;
|
|||||||
mod commands;
|
mod commands;
|
||||||
mod db;
|
mod db;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod mystem;
|
|
||||||
mod utils;
|
|
||||||
mod handlers;
|
mod handlers;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use mystem::MyStem;
|
use mystem::MyStem;
|
||||||
|
|
||||||
@ -39,13 +38,23 @@ async fn main() -> Result<(), errors::Error> {
|
|||||||
let api = Api::new(token.clone());
|
let api = Api::new(token.clone());
|
||||||
let mut stream = api.stream();
|
let mut stream = api.stream();
|
||||||
let me = api.send(GetMe).await?;
|
let me = api.send(GetMe).await?;
|
||||||
info!("GetMe result: Username: {}, First Name: {}, ID {}", me.username.as_ref().unwrap(), me.first_name, me.id);
|
info!(
|
||||||
|
"GetMe result: Username: {}, First Name: {}, ID {}",
|
||||||
|
me.username.as_ref().unwrap(),
|
||||||
|
me.first_name,
|
||||||
|
me.id
|
||||||
|
);
|
||||||
while let Some(update) = stream.next().await {
|
while let Some(update) = stream.next().await {
|
||||||
let update = update?;
|
let update = update?;
|
||||||
if let UpdateKind::Message(message) = update.kind {
|
if let UpdateKind::Message(message) = update.kind {
|
||||||
db::add_conf(message.clone()).await?;
|
db::add_conf(message.clone()).await?;
|
||||||
db::add_user(message.clone()).await?;
|
db::add_user(message.clone()).await?;
|
||||||
handlers::handler(api.clone(), message, token.clone(), &mut mystem, me.clone()).await?;
|
match handlers::handler(api.clone(), message, token.clone(), &mut mystem, me.clone())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => warn!("An error occurred handling command. {:?}", e),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
use crate::errors;
|
|
||||||
use serde_json::Value;
|
|
||||||
use std::io::{Error, Write, BufReader, prelude::*};
|
|
||||||
use subprocess::{Popen, PopenConfig, PopenError, Redirection};
|
|
||||||
|
|
||||||
pub struct MyStem {
|
|
||||||
pub process: Popen,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MyStem {
|
|
||||||
pub fn new() -> Result<Self, PopenError> {
|
|
||||||
Ok(Self {
|
|
||||||
process: MyStem::open_process()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn open_process() -> Result<Popen, PopenError> {
|
|
||||||
Popen::create(
|
|
||||||
&["mystem", "-d", "--format", "json"],
|
|
||||||
PopenConfig {
|
|
||||||
stdout: Redirection::Pipe,
|
|
||||||
stdin: Redirection::Pipe,
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn terminate(&mut self) -> Result<(), Error> {
|
|
||||||
self.process.terminate()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_must_use)]
|
|
||||||
pub async fn stemming(&mut self, text: String) -> Result<Vec<String>, errors::Error> {
|
|
||||||
if let Some(exit_status) = self.process.poll() {
|
|
||||||
warn!(
|
|
||||||
"MyStem process exited with: {:?}. Restarting...",
|
|
||||||
exit_status
|
|
||||||
);
|
|
||||||
self.process = MyStem::open_process()?;
|
|
||||||
}
|
|
||||||
let mut words: Vec<String> = vec![];
|
|
||||||
let clean_text = format!("{}{}", text.trim(), "\n");
|
|
||||||
self.process
|
|
||||||
.stdin
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.write(clean_text.as_bytes());
|
|
||||||
let mut contents = String::new();
|
|
||||||
let mut buf_reader = BufReader::new(self.process.stdout.as_ref().unwrap());
|
|
||||||
buf_reader.read_line(&mut contents);
|
|
||||||
|
|
||||||
match Some(contents) {
|
|
||||||
Some(contents) => {
|
|
||||||
let v: Vec<Value> = match serde_json::from_str(contents.as_str()) {
|
|
||||||
Ok(val) => val,
|
|
||||||
Err(_) => return Ok(vec![]),
|
|
||||||
};
|
|
||||||
for i in v {
|
|
||||||
words.push(i["analysis"][0]["lex"].to_string().replace("\"", ""));
|
|
||||||
}
|
|
||||||
words.retain(|x| x != "null");
|
|
||||||
debug!(
|
|
||||||
"Mystem PID: {}. Parsed words: {}.",
|
|
||||||
self.process.pid().unwrap(),
|
|
||||||
words.join(", ")
|
|
||||||
);
|
|
||||||
Ok(words)
|
|
||||||
}
|
|
||||||
None => return Ok(vec![]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,15 +13,14 @@ pub(crate) fn get_title(message: &Message) -> String {
|
|||||||
match &message.chat {
|
match &message.chat {
|
||||||
MessageChat::Supergroup(chat) => chat.title.clone(),
|
MessageChat::Supergroup(chat) => chat.title.clone(),
|
||||||
MessageChat::Group(chat) => chat.title.clone(),
|
MessageChat::Group(chat) => chat.title.clone(),
|
||||||
MessageChat::Private(_) => format!("PRIVATE"),
|
MessageChat::Private(_) => "PRIVATE".to_string(),
|
||||||
_ => "PRIVATE".to_string(),
|
_ => "PRIVATE".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn create_dir(dir: &String) -> () {
|
pub(crate) async fn create_dir(dir: &str) {
|
||||||
match fs_create_dir(dir) {
|
if fs_create_dir(dir).is_ok() {
|
||||||
Ok(_) => info!("Dir {} created.", dir),
|
info!("Dir {} created.", dir)
|
||||||
Err(_) => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user