mirror of
https://github.com/house-of-vanity/desubot.git
synced 2025-07-08 13:04:06 +00:00
Compare commits
54 Commits
Author | SHA1 | Date | |
---|---|---|---|
1facef6897 | |||
428416a2a3 | |||
77dec205f1 | |||
6c761d7576 | |||
865fd3bbe4 | |||
30bdb23a32 | |||
f97562e9b7 | |||
2d000101c2 | |||
a26d227190 | |||
cc44f0e23b | |||
96df636195 | |||
a48e25800c | |||
36660d384d | |||
0d24976ec2 | |||
6ae3b2af1f | |||
a39f6a8c2a | |||
788c2cbbd4 | |||
9d5e5a3217 | |||
945da05794 | |||
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 |
27
.github/workflows/automerge.yml
vendored
Normal file
27
.github/workflows/automerge.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
name: automerge
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types:
|
||||||
|
- labeled
|
||||||
|
- unlabeled
|
||||||
|
- synchronize
|
||||||
|
- opened
|
||||||
|
- edited
|
||||||
|
- ready_for_review
|
||||||
|
- reopened
|
||||||
|
- unlocked
|
||||||
|
pull_request_review:
|
||||||
|
types:
|
||||||
|
- submitted
|
||||||
|
check_suite:
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
status: {}
|
||||||
|
jobs:
|
||||||
|
automerge:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: automerge
|
||||||
|
uses: "pascalgn/automerge-action@v0.13.0"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
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
21
Cargo.toml
21
Cargo.toml
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "desubot"
|
name = "desubot"
|
||||||
version = "0.1.0"
|
version = "0.5.5"
|
||||||
authors = ["AB <ab@hexor.ru>"]
|
authors = ["AB <ab@hexor.ru>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@ -9,26 +9,33 @@ edition = "2018"
|
|||||||
[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"
|
telegram-bot = "0.8.0"
|
||||||
|
silicon = "0.4.0"
|
||||||
hyper = "0.13"
|
hyper = "0.13"
|
||||||
hyper-tls = { version = "0.4", optional = true }
|
hyper-tls = { version = "0.4", optional = true }
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
hyper-rustls = { version = "0.19", optional = true }
|
hyper-rustls = { version = "0.19", optional = true }
|
||||||
|
rusqlite = { version = "0.24.2", features = ["bundled"]}
|
||||||
rusqlite = { version = "0.24.1", features = ["bundled"]}
|
|
||||||
html-escape = "0.2"
|
html-escape = "0.2"
|
||||||
|
regex = "1"
|
||||||
reqwest = "0.10.9"
|
reqwest = "0.10.9"
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
sha1 = "*"
|
sha1 = "0.6.0"
|
||||||
env_logger = "0.7"
|
env_logger = "0.7"
|
||||||
log = { version = "^0.4.5", features = ["std"] }
|
log = { version = "^0.4.5", features = ["std"] }
|
||||||
subprocess = "0.2.6"
|
subprocess = "0.2.6"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
markov = "1.1.0"
|
markov = "1.1.0"
|
||||||
rand = "0.7.3"
|
rand = "0.7.3"
|
||||||
|
mystem = "^0.2"
|
||||||
|
#mystem = { path = "../mystem-rs" }
|
||||||
|
async-trait = "0.1.42"
|
||||||
|
sqlparser = "0.7.0"
|
||||||
|
|
||||||
|
[dependencies.syntect]
|
||||||
|
version = "4.4"
|
||||||
|
default-features = false
|
||||||
|
features = ["parsing", "dump-load", "regex-onig"]
|
||||||
|
9
README
9
README
@ -7,9 +7,8 @@ Telegram bot with light group statistic and heavy spy features.
|
|||||||
* /here command to mention all members.
|
* /here command to mention all members.
|
||||||
* Alongside with saving whole message bot perform blacklist filter and stemming for every word (only Russian). "Красивую собаку мыли негры" -> "красивый собака мыть негр"
|
* Alongside with saving whole message bot perform blacklist filter and stemming for every word (only Russian). "Красивую собаку мыли негры" -> "красивый собака мыть негр"
|
||||||
* Generate sentences using Markov Chains trained on history with /markov_all.
|
* Generate sentences using Markov Chains trained on history with /markov_all.
|
||||||
|
* Syntax highlighting for CODE exported to image.
|
||||||
|
|
||||||
== TODO ==
|
== Important ==
|
||||||
* Syntax highlighting for code exported to image.
|
* 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.
|
||||||
== Notes ==
|
|
||||||
* 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.
43
assets/help_text.rs
Normal file
43
assets/help_text.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#[allow(dead_code)]
|
||||||
|
static CODE_HELP: &str = "<b>Code highlighter</b>
|
||||||
|
|
||||||
|
<i>Usage</i>
|
||||||
|
<pre>/code
|
||||||
|
<CODE>
|
||||||
|
#<lang - JS by default> #<theme - Dracula 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
|
||||||
|
";
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub static SQL_HELP: &str = "<b>Perform an SQL command</b>
|
||||||
|
<i>* Only one sentence per message.
|
||||||
|
* Only SELECT command.
|
||||||
|
* Max result length is 100 lines. Use LIMIT 100.
|
||||||
|
* SQLITE syntax is available only.</i>";
|
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>
|
575
src/commands.rs
575
src/commands.rs
@ -1,13 +1,206 @@
|
|||||||
|
#![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::highlighting::Theme;
|
||||||
|
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, UserId};
|
||||||
|
|
||||||
pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> {
|
include!("../assets/help_text.rs");
|
||||||
let members: Vec<telegram_bot::User> = db::get_members(message.chat.id()).unwrap();
|
|
||||||
|
pub struct Here {
|
||||||
|
pub data: String,
|
||||||
|
}
|
||||||
|
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!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
|
let mut sql = self.data.clone();
|
||||||
|
debug!("PIZDA - {}", sql);
|
||||||
|
if sql == "/sql" || sql == "/sql-" {
|
||||||
|
return Ok(SQL_HELP.to_string());
|
||||||
|
}
|
||||||
|
let is_head = if sql.starts_with('-') {
|
||||||
|
sql = sql.replacen("-", "", 1);
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
true
|
||||||
|
};
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Execute for Here {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
let members: Vec<telegram_bot::User> =
|
||||||
|
db::get_members(message.chat.id(), 60).unwrap_or(vec![telegram_bot::User {
|
||||||
|
id: UserId::new(124317807),
|
||||||
|
first_name: "Ultradesu".to_string(),
|
||||||
|
last_name: None,
|
||||||
|
username: None,
|
||||||
|
is_bot: false,
|
||||||
|
language_code: None,
|
||||||
|
}]);
|
||||||
for u in &members {
|
for u in &members {
|
||||||
debug!("Found user {:?} in chat {}", u, message.chat.id());
|
debug!("Found user {:?} in chat {}", u, message.chat.id());
|
||||||
}
|
}
|
||||||
@ -31,12 +224,27 @@ pub(crate) async fn here(api: Api, message: Message) -> Result<(), Error> {
|
|||||||
Ok(_) => debug!("/here command sent to {}", message.chat.id()),
|
Ok(_) => debug!("/here command sent to {}", message.chat.id()),
|
||||||
Err(_) => warn!("/here command sent failed to {}", message.chat.id()),
|
Err(_) => warn!("/here 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn top(api: Api, message: Message) -> Result<(), Error> {
|
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 top = db::get_top(&message).await?;
|
||||||
let mut msg = "<b>Your top using words:</b>\n<pre>".to_string();
|
let mut msg = "<b>Your top using words:</b>\n<pre>".to_string();
|
||||||
let mut counter = 1;
|
let mut counter = 1;
|
||||||
@ -55,13 +263,28 @@ pub(crate) async fn top(api: Api, message: Message) -> Result<(), Error> {
|
|||||||
Ok(_) => debug!("/top command sent to {}", message.chat.id()),
|
Ok(_) => debug!("/top command sent to {}", message.chat.id()),
|
||||||
Err(_) => warn!("/top command sent failed 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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn markov_all(api: Api, message: Message) -> Result<(), Error> {
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
let messages = db::get_random_messages().await?;
|
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();
|
let mut chain = Chain::new();
|
||||||
chain.feed(messages);
|
chain.feed(messages);
|
||||||
let mut sentences = chain.generate();
|
let mut sentences = chain.generate();
|
||||||
@ -81,8 +304,25 @@ pub(crate) async fn markov_all(api: Api, message: Message) -> Result<(), Error>
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn markov(api: Api, message: Message) -> Result<(), Error> {
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
let messages = db::get_random_messages_group(&message).await?;
|
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();
|
let mut chain = Chain::new();
|
||||||
chain.feed(messages);
|
chain.feed(messages);
|
||||||
let mut sentences = chain.generate();
|
let mut sentences = chain.generate();
|
||||||
@ -101,3 +341,314 @@ pub(crate) async fn markov(api: Api, message: Message) -> Result<(), Error> {
|
|||||||
//api.send(message.from.text("Private text")).await?;
|
//api.send(message.from.text("Private text")).await?;
|
||||||
Ok(())
|
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()),
|
||||||
|
);
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl Execute for Code {
|
||||||
|
async fn exec(&self, api: &Api, message: &Message) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
async fn exec_with_result(&self, api: &Api, message: &Message) -> Result<String, Error> {
|
||||||
|
let mut lines: Vec<String> = self
|
||||||
|
.data
|
||||||
|
.trim()
|
||||||
|
.split("\n")
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect();
|
||||||
|
if lines.len() >= 81 {
|
||||||
|
return Err(CodeHighlightningError);
|
||||||
|
}
|
||||||
|
let last_line = &lines[lines.len() - 1];
|
||||||
|
|
||||||
|
let tags = last_line
|
||||||
|
.trim()
|
||||||
|
.split(|s| s == ' ' || s == '\n')
|
||||||
|
.filter(|s| s.starts_with("#"))
|
||||||
|
.map(|s| s.to_string().replace("#", ""))
|
||||||
|
.map(|s| s.to_string().replace("_", " "))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
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)
|
||||||
|
.line_offset(1)
|
||||||
|
.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())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn exec_mystem(
|
||||||
|
&self,
|
||||||
|
api: &Api,
|
||||||
|
message: &Message,
|
||||||
|
mystem: &mut MyStem,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
125
src/db.rs
125
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,18 +135,74 @@ pub(crate) async fn get_random_messages_group(
|
|||||||
Ok(messages)
|
Ok(messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_members(id: telegram_bot::ChatId) -> Result<Vec<telegram_bot::User>> {
|
#[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 conn = open()?;
|
||||||
let mut stmt = conn.prepare_cached(
|
let mut stmt = conn.prepare_cached(
|
||||||
"
|
"
|
||||||
SELECT DISTINCT(u.username), u.id, u.first_name, u.last_name, u.date
|
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, limit: u32) -> Result<Vec<telegram_bot::User>> {
|
||||||
|
let where_statement = if limit > 0 {
|
||||||
|
format!("and days_seen <= {}", limit)
|
||||||
|
} else {
|
||||||
|
"".into()
|
||||||
|
};
|
||||||
|
debug!("{}", where_statement);
|
||||||
|
let conn = open()?;
|
||||||
|
let mut stmt = conn.prepare_cached(&format!(
|
||||||
|
"
|
||||||
|
SELECT DISTINCT(u.username), u.id, u.first_name, u.last_name, u.date,
|
||||||
|
(strftime('%s','now')-r.date)/60/60/24 as days_seen
|
||||||
FROM relations r
|
FROM relations r
|
||||||
JOIN user u
|
JOIN user u
|
||||||
ON u.id = r.user_id
|
ON u.id = r.user_id
|
||||||
LEFT JOIN conf c
|
LEFT JOIN conf c
|
||||||
ON r.conf_id = c.id
|
ON r.conf_id = c.id
|
||||||
WHERE c.id = :id",
|
WHERE c.id = :id
|
||||||
)?;
|
{}
|
||||||
|
GROUP BY u.id
|
||||||
|
ORDER BY r.date DESC",
|
||||||
|
where_statement
|
||||||
|
))?;
|
||||||
let mut rows = stmt.query_named(&[(":id", &id.to_string())])?;
|
let mut rows = stmt.query_named(&[(":id", &id.to_string())])?;
|
||||||
let mut users = Vec::new();
|
let mut users = Vec::new();
|
||||||
|
|
||||||
@ -169,7 +225,7 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
|
|||||||
|
|
||||||
match get_conf(message.chat.id()) {
|
match get_conf(message.chat.id()) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
//info!("Group found: {:?}", message.chat.id());
|
debug!("Group found: {:?}", message.chat.id());
|
||||||
let update = Conf {
|
let update = Conf {
|
||||||
id: message.chat.id(),
|
id: message.chat.id(),
|
||||||
title,
|
title,
|
||||||
@ -183,10 +239,10 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
|
|||||||
id = :id",
|
id = :id",
|
||||||
)?;
|
)?;
|
||||||
stmt.execute_named(&[(":id", &update.id.to_string()), (":title", &update.title)])?;
|
stmt.execute_named(&[(":id", &update.id.to_string()), (":title", &update.title)])?;
|
||||||
//info!("Conf {:?} updated: {:?}", update.title, get_conf(update.id));
|
debug!("Conf {:?} updated: {:?}", update.title, get_conf(update.id));
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
//info!("Group didn't found: {:?}", message.chat.id());
|
debug!("Group didn't found: {:?}", message.chat.id());
|
||||||
|
|
||||||
let update = Conf {
|
let update = Conf {
|
||||||
id: message.chat.id(),
|
id: message.chat.id(),
|
||||||
@ -205,7 +261,7 @@ pub(crate) async fn add_conf(message: Message) -> Result<(), Error> {
|
|||||||
(":title", &update.title),
|
(":title", &update.title),
|
||||||
(":date", &unix_time),
|
(":date", &unix_time),
|
||||||
])?;
|
])?;
|
||||||
//info!("Conf {:?} added: {:?}", update.title, get_conf(update.id));
|
debug!("Conf {:?} added: {:?}", update.title, get_conf(update.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -238,7 +294,11 @@ pub(crate) async fn add_user(message: Message) -> Result<(), Error> {
|
|||||||
(":first_name", &update.first_name),
|
(":first_name", &update.first_name),
|
||||||
(":last_name", &update.last_name),
|
(":last_name", &update.last_name),
|
||||||
])?;
|
])?;
|
||||||
//println!("User {} updated: {:?}", update.first_name, get_user(user.id));
|
debug!(
|
||||||
|
"User {} updated: {:?}",
|
||||||
|
update.first_name,
|
||||||
|
get_user(update.id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let unix_time = SystemTime::now()
|
let unix_time = SystemTime::now()
|
||||||
@ -265,7 +325,7 @@ pub(crate) async fn add_user(message: Message) -> Result<(), Error> {
|
|||||||
(":last_name", &user.last_name),
|
(":last_name", &user.last_name),
|
||||||
(":date", &unix_time),
|
(":date", &unix_time),
|
||||||
])?;
|
])?;
|
||||||
//println!("User added: {:?}", user);
|
debug!("User added: {:?}", user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -300,14 +360,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 +379,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 +413,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 +432,22 @@ pub(crate) async fn add_sentence(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Save stemmed words
|
// Save stemmed words
|
||||||
let words = mystem.stemming(text).await?;
|
debug!("Going to stem: {}", text);
|
||||||
|
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 +486,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
116
src/handlers.rs
116
src/handlers.rs
@ -1,10 +1,12 @@
|
|||||||
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,
|
||||||
@ -13,7 +15,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 +24,101 @@ pub async fn handler(
|
|||||||
title,
|
title,
|
||||||
&message.from.id,
|
&message.from.id,
|
||||||
&message.from.first_name,
|
&message.from.first_name,
|
||||||
data
|
data.replace("\n", " ")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let cleaned_message = data.replace(&format!("@{}", me.clone().username.unwrap()), "");
|
||||||
|
match cleaned_message.as_str() {
|
||||||
|
s if s.to_string().starts_with("/code") => {
|
||||||
|
match {
|
||||||
|
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_HELP).parse_mode(ParseMode::Html))
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s if s.contains("/here") || s.contains("@here") => {
|
||||||
db::add_sentence(&message, mystem).await?;
|
db::add_sentence(&message, mystem).await?;
|
||||||
match data.as_str() {
|
Here {
|
||||||
"/here" => commands::here(api, message).await?,
|
data: "".to_string(),
|
||||||
"/top" => commands::top(api, message).await?,
|
}
|
||||||
"/stat" => commands::top(api, message).await?,
|
.exec(&api, &message)
|
||||||
"/markov_all" => commands::markov_all(api, message).await?,
|
.await?
|
||||||
"/markov" => commands::markov(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 +129,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 +142,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