Merge branch 'master' into whiteboards

This commit is contained in:
Peng Xiao
2022-07-10 02:25:02 +08:00
14 changed files with 200 additions and 94 deletions

View File

@@ -13,7 +13,7 @@ on:
- beta
- nightly
- non-release
default: "beta"
default: "non-release"
git-ref:
description: "Release Git Ref (Which branch or tag to build?)"
required: true

View File

@@ -67,9 +67,9 @@ you're hoping to have this list drop to zero.
Almost all translations are pretty quick. The only exceptions to this are the keys `:tutorial/text` and `:tutorial/dummy-notes`. These reference files that are part of the onboarding tutorial. Most languages don't have this translated. If you are willing to do this, we would be happy to have this translated.
## Fix Mistakes
## Fix Untranslated
There is a lot to translate and sometimes we make mistakes. For example, we may leave a string untranslated. To see what translation keys are still left in English:
There is a lot to translate and sometimes we forget to translate a string. To see what translation keys are still left in English:
```
$ bb lang:duplicates
@@ -82,8 +82,11 @@ Keys with duplicate values found:
| :no | No |
```
Sometimes, we typo the translation key. If that happens, the github CI job will
detect this error and helpfully show you what was typoed.
## Fix Mistakes
Sometimes, we typo the translation key. If that happens, the github CI step of
`bb lang:invalid-translations` will detect this error and helpfully show you
what was typoed.
## Add a Language

View File

@@ -5,7 +5,8 @@ This page describes development practices for this codebase.
## Linting
Most of our linters require babashka. Before running them, please install
https://github.com/babashka/babashka#installation.
https://github.com/babashka/babashka#installation. To invoke all the linters in
this section, run `bb dev:lint`.
### Clojure code
@@ -49,7 +50,7 @@ and understand them. To run this linter:
bb lint:large-vars
```
To configure the linter, see its `config` var.
To configure the linter, see the `[:tasks/config :large-vars]` path of bb.edn.
### Datalog linting
@@ -60,6 +61,11 @@ queries and rules. Our queries are linted through clj-kondo and
[datalog-parser](https://github.com/lambdaforge/datalog-parser). clj-kondo will
error if it detects an invalid query.
### Invalid translations
Our translations can be configured incorrectly. We can catch some of these
mistakes [as noted here](./contributing-to-translations.md#fix-mistakes).
## Testing
We have unit and end to end tests.

View File

@@ -228,7 +228,7 @@ export type SimpleCommandKeybinding = {
export type SettingSchemaDesc = {
key: string
type: 'string' | 'number' | 'boolean' | 'enum' | 'object'
type: 'string' | 'number' | 'boolean' | 'enum' | 'object' | 'heading'
default: string | number | boolean | Array<any> | object | null
title: string
description: string // support markdown

View File

@@ -43,6 +43,8 @@
:win win})))
(defn open-url-handler
"win - the main window instance (first renderer process)
url - the input URL"
[win url]
(.info logger "open-url" (str {:url url}))

View File

@@ -2,7 +2,7 @@
(:require [electron.handler :as handler]
[electron.state :as state]
[electron.window :as win]
[electron.utils :refer [send-to-renderer] :as utils]
[electron.utils :refer [send-to-renderer send-to-focused-renderer] :as utils]
[clojure.string :as string]
[promesa.core :as p]))
@@ -58,22 +58,24 @@
(graph-identifier-error-handler graph-identifier))))
(defn- x-callback-url-handler
[^js parsed-url]
"win - a window used for fallback (main window is prefered)"
[^js win parsed-url]
(let [action (.-pathname parsed-url)]
(cond
(= action "/quickCapture")
(let [[url title content] (get-URL-decoded-params parsed-url ["url" "title" "content"])]
(send-to-renderer "quickCapture" {:url url
:title title
:content content}))
(send-to-focused-renderer "quickCapture" {:url url
:title title
:content content} win))
:else
(send-to-renderer "notification" {:type "error"
:payload (str "Unimplemented x-callback-url action: `"
action
"`.")}))))
(send-to-focused-renderer "notification" {:type "error"
:payload (str "Unimplemented x-callback-url action: `"
action
"`.")} win))))
(defn logseq-url-handler
"win - the main window"
[^js win parsed-url]
(let [url-host (.-host parsed-url)] ;; return "" when no pathname provided
(cond
@@ -81,7 +83,7 @@
(send-to-renderer win "loginCallback" (.get (.-searchParams parsed-url) "code"))
(= "x-callback-url" url-host)
(x-callback-url-handler parsed-url)
(x-callback-url-handler win parsed-url)
;; identifier of graph in local
(= "graph" url-host)

View File

@@ -6,7 +6,7 @@
[cljs-bean.core :as bean]
["electron" :refer [app BrowserWindow]]))
(defonce *win (atom nil))
(defonce *win (atom nil)) ;; The main window
(defonce mac? (= (.-platform js/process) "darwin"))
(defonce win32? (= (.-platform js/process) "win32"))
(defonce linux? (= (.-platform js/process) "linux"))
@@ -112,7 +112,8 @@
(defn send-to-renderer
"Notice: pass the `window` parameter if you can. Otherwise, the message
will not be received if there's no focused window."
will not be received if there's no focused window.
Use `send-to-focused-renderer` instead if you want to set a window for fallback"
([kind payload]
(send-to-renderer (get-focused-window) kind payload))
([window kind payload]
@@ -120,6 +121,13 @@
(.. ^js window -webContents
(send (name kind) (bean/->js payload))))))
(defn send-to-focused-renderer
"Try to send to focused window. If no focused window, fallback to the `fallback-win`"
([kind payload fallback-win]
(let [focused-win (get-focused-window)
win (if focused-win focused-win fallback-win)]
(send-to-renderer win kind payload))))
(defn get-graph-dir
"required by all internal state in the electron section"
[graph-name]

View File

@@ -2727,29 +2727,32 @@
[state]
(let [[config query] (:rum/args state)
repo (state/get-current-repo)
result-atom (atom nil)
query-atom (if (:dsl-query? config)
(let [q (:query query)
form (safe-read-string q false)]
(cond
;; Searches like 'foo' or 'foo bar' come back as symbols
;; and are meant to go directly to full text search
(and (util/electron?) (symbol? form)) ; full-text search
(p/let [blocks (search/block-search repo (string/trim (str form)) {:limit 30})]
(when (seq blocks)
(let [result (db/pull-many (state/get-current-repo) '[*] (map (fn [b] [:block/uuid (uuid (:block/uuid b))]) blocks))]
(reset! result-atom result))))
result-atom (or (:query-atom state) (atom nil))
[full-text-search? query-atom] (if (:dsl-query? config)
(let [q (:query query)
form (safe-read-string q false)]
(cond
;; Searches like 'foo' or 'foo bar' come back as symbols
;; and are meant to go directly to full text search
(and (util/electron?) (symbol? form)) ; full-text search
[true
(p/let [blocks (search/block-search repo (string/trim (str form)) {:limit 30})]
(when (seq blocks)
(let [result (db/pull-many (state/get-current-repo) '[*] (map (fn [b] [:block/uuid (uuid (:block/uuid b))]) blocks))]
(reset! result-atom result))))]
(symbol? form)
(atom nil)
(symbol? form)
[false (atom nil)]
:else
(query-dsl/query (state/get-current-repo) q)))
(db/custom-query query))
:else
[false (query-dsl/query (state/get-current-repo) q)]))
[false (db/custom-query query)])
query-atom (if (instance? Atom query-atom)
query-atom
result-atom)]
(assoc state :query-atom query-atom)))
(assoc state
:query-atom query-atom
:full-text-search? full-text-search?)))
(rum/defcs ^:large-vars/cleanup-todo custom-query* < rum/reactive
{:will-mount trigger-custom-query!
@@ -2809,21 +2812,30 @@
[:div.custom-query.mt-4 (get config :attr {})
(ui/foldable
[:div.custom-query-title.flex.justify-between.w-full
[:div [:span.title-text (cond
(vector? title) title
(string? title) (inline-text config
(get-in config [:block :block/format] :markdown)
title)
:else title)]
[:div.flex.items-center
(when (:full-text-search? state)
[:a.control.fade-link.mr-1.inline-flex
{:title "Refresh query result"
:on-mouse-down (fn [e]
(util/stop e)
(trigger-custom-query! state))}
(ui/icon "refresh" {:style {:font-size 20}})])
[:span.title-text (cond
(vector? title) title
(string? title) (inline-text config
(get-in config [:block :block/format] :markdown)
title)
:else title)]
[:span.opacity-60.text-sm.ml-2.results-count
(str (count transformed-query-result) " results")]]
;;insert an "edit" button in the query view
(when-not built-in?
[:a.opacity-70.hover:opacity-100.svg-small.inline
{:on-mouse-down (fn [e]
(util/stop e)
(editor-handler/edit-block! current-block :max (:block/uuid current-block)))}
svg/edit])]
[:a.opacity-70.hover:opacity-100.svg-small.inline
{:on-mouse-down (fn [e]
(util/stop e)
(editor-handler/edit-block! current-block :max (:block/uuid current-block)))}
svg/edit])]
(fn []
[:div
(when (and current-block (not view-f) (nil? table-view?))

View File

@@ -465,6 +465,12 @@
right: 8px;
}
.heading-item {
margin: 12px 12px 6px;
font-weight: bold;
border-bottom: 1px solid var(--ls-border-color, #738694);
}
.desc-item {
padding: 12px 12px 6px;
@@ -783,7 +789,7 @@
max-height: 80vh;
overflow-y: auto;
}
.menu-link {
padding: 3px 5px;
}

View File

@@ -74,6 +74,12 @@
[:small.pl-1.flex-1 description]
[:div.pl-1 (edit-settings-file pid nil)]]])
(rum/defc render-item-heading
[{:keys [title]}]
[:div.heading-item
[:h2 title]])
(rum/defc settings-container
[schema ^js pl]
(let [^js _settings (.-settings pl)
@@ -107,6 +113,7 @@
#{:boolean} (render-item-toggle val desc update-setting!)
#{:enum} (render-item-enum val desc update-setting!)
#{:object} (render-item-object val desc pid)
#{:heading} (render-item-heading desc)
[:p (str "#Not Handled#" key)]))]

View File

@@ -40,11 +40,18 @@
:sub (fn sub [a b] (-> a (.minus b)))
:mul (fn mul [a b] (-> a (.multipliedBy b)))
:div (fn div [a b] (-> a (.dividedBy b)))
:pow (fn pow [a b] (-> a (.exponentiatedBy b)))
:pow (fn pow [a b] (if (.isInteger b)
(.exponentiatedBy a b)
#?(:clj (java.lang.Math/pow a b)
:cljs (bn/BigNumber (js/Math.pow a b)))))
:abs (fn abs [a] (.abs a))
:sqrt (fn abs [a] (.sqrt a))
:log (fn log [a]
#?(:clj (java.lang.Math/log10 a) :cljs (bn/BigNumber (js/Math.log10 a))))
:ln (fn ln [a]
#?(:clj (java.lang.Math/log a) :cljs (bn/BigNumber (js/Math.log a))))
:exp (fn ln [a]
#?(:clj (java.lang.Math/exp a) :cljs (bn/BigNumber (js/Math.exp a))))
:sin (fn sin [a]
#?(:clj (java.lang.Math/sin a) :cljs (bn/BigNumber(js/Math.sin a))))
:cos (fn cos [a]
@@ -61,6 +68,7 @@
(swap! env assoc var val)
val)
:toassign str/trim
:comment (constantly nil)
:variable (fn resolve [var]
(let [var (str/trim var)]
(or (get @env var)
@@ -79,12 +87,17 @@
(catch #?(:clj Exception :cljs js/Error) e
e))))
(defn assign-last-value [env val]
(when-not (nil? val)
(swap! env assoc "last" val))
val)
(defn eval-lines [s]
{:pre [(string? s)]}
(let [env (new-env)]
(mapv (fn [line]
(when-not (str/blank? line)
(eval env (parse line))))
(assign-last-value env (eval env (parse line)))))
(str/split-lines s))))
;; ======================================================================

View File

@@ -5,6 +5,7 @@
[datascript.core :as d]
[frontend.commands :as commands]
[frontend.config :as config]
[frontend.context.i18n :refer [t]]
[frontend.date :as date]
[frontend.db :as db]
[logseq.db.schema :as db-schema]
@@ -719,8 +720,9 @@
(fn [chosen _click?]
(state/clear-editor-action!)
(let [wrapped? (= "[[" (gp-util/safe-subs edit-content (- pos 2) pos))
chosen (if (string/starts-with? chosen "New page: ") ;; FIXME: What if a page named "New page: XXX"?
(subs chosen 10)
prefix (str (t :new-page) ": ")
chosen (if (string/starts-with? chosen prefix) ;; FIXME: What if a page named "New page: XXX"?
(string/replace-first chosen prefix "")
chosen)
chosen (if (and (util/safe-re-find #"\s+" chosen) (not wrapped?))
(util/format "[[%s]]" chosen)
@@ -740,8 +742,9 @@
:forward-pos forward-pos})))
(fn [chosen _click?]
(state/clear-editor-action!)
(let [chosen (if (string/starts-with? chosen "New page: ")
(subs chosen 10)
(let [prefix (str (t :new-page) ": ")
chosen (if (string/starts-with? chosen prefix)
(string/replace-first chosen prefix "")
chosen)
page-ref-text (get-page-ref-text chosen)]
(editor-handler/insert-command! id

View File

@@ -1,28 +1,32 @@
<start> = assignment | expr
expr = add-sub
<add-sub> = pow-term | mul-div | add | sub | variable
<start> = assignment | expr | comment
expr = add-sub comment
comment = <#'\s*(#.*$)?'>
<add-sub> = pow-term | mul-div | add | sub | variable
add = add-sub <'+'> mul-div
sub = add-sub <'-'> mul-div
<mul-div> = pow-term | mul | div
mul = mul-div <'*'> pow-term
div = mul-div <'/'> pow-term
<pow-term> = pow | term
pow = pow-term <'^'> term
<trig> = sin | cos | tan | acos | asin | atan
pow = posterm <'^'> pow-term
<function> = log | ln | exp | sqrt | abs | sin | cos | tan | acos | asin | atan
log = <#'\s*'> <'log('> expr <')'> <#'\s*'>
ln = <#'\s*'> <'ln('> expr <')'> <#'\s*'>
exp = <#'\s*'> <'exp('> expr <')'> <#'\s*'>
sqrt = <#'\s*'> <'sqrt('> expr <')'> <#'\s*'>
abs = <#'\s*'> <'abs('> expr <')'> <#'\s*'>
sin = <#'\s*'> <'sin('> expr <')'> <#'\s*'>
cos = <#'\s*'> <'cos('> expr <')'> <#'\s*'>
tan = <#'\s*'> <'tan('> expr <')'> <#'\s*'>
atan = <#'\s*'> <'atan('> expr <')'> <#'\s*'>
acos = <#'\s*'> <'acos('> expr <')'> <#'\s*'>
asin = <#'\s*'> <'asin('> expr <')'> <#'\s*'>
<posterm> = log | ln | trig | percent | scientific | number | variable | <#'\s*'> <'('> expr <')'> <#'\s*'>
negterm = <#'\s*'> <'-'> posterm
<posterm> = function | percent | scientific | number | variable | <#'\s*'> <'('> expr <')'> <#'\s*'>
negterm = <#'\s*'> <'-'> posterm | <#'\s*'> <'-'> pow
<term> = negterm | posterm
scientific = #'\s*[0-9]+\.?[0-9]*(e|E)-?[0-9]+()\s*'
number = #'\s*\d+(,\d+)*(\.\d*)?\s*'
scientific = #'\s*[0-9]*\.?[0-9]+(e|E)[\-\+]?[0-9]+()\s*'
number = #'\s*(\d+(,\d+)*(\.\d*)?|\d*\.\d+)\s*'
percent = number <'%'> <#'\s*'>
variable = #'\s*[a-zA-Z]+(\_+[a-zA-Z]+)*\s*'
toassign = #'\s*[a-zA-Z]+(\_+[a-zA-Z]+)*\s*'
variable = #'\s*_*[a-zA-Z]+[_a-zA-Z0-9]*\s*'
toassign = #'\s*_*[a-zA-Z]+[_a-zA-Z0-9]*\s*'
assignment = toassign <#'\s*'> <'='> <#'\s*'> expr

View File

@@ -19,7 +19,11 @@
98123 "98123"
1.0 " 1.0 "
22.1124131 "22.1124131"
100.01231 " 100.01231 ")
100.01231 " 100.01231 "
0.01231 " .01231 "
0.015 ".015 "
-0.2 "-.2"
-0.3 "- .3")
(testing "even when they have the commas in the wrong place"
(are [value expr] (= value (run expr))
98123 "9812,3"
@@ -62,15 +66,6 @@
2.0 "2*100%"
0.01 "2%/2"
500e3 "50% * 1e6"))
(testing "power"
(are [value expr] (= value (run expr))
1.0 "1 ^ 0"
4.0 "2^2 "
27.0 " 3^ 3"
0.125 " 2^ -3"
16.0 "2 ^ 2 ^ 2"
256.0 "4.000 ^ 4.0"
4096.0 "200% ^ 12"))
(testing "operator precedence"
(are [value expr] (= value (run expr))
1 "1 + 0 * 2"
@@ -90,9 +85,39 @@
12.3 "123.0e-1"
-12.3 "-123.0e-1"
12.3 "123.0E-1"
2.0 "1e0 + 1e0"))
(testing "scientific functions"
12300 "123.0E+2"
2.0 "1e0 + 1e0"
10 ".1e2"
0.001 ".1e-2"
-0.045 "-.45e-1"
-210 "-.21e3"))
(testing "avoiding rounding errors"
(are [value expr] (= value (run expr))
3.3 "1.1 + 2.2"
2.2 "3.3 - 1.1"
0.0001 "1/10000"
1e-7 "1/10000000")))
(deftest scientific-functions
(testing "power"
(are [value expr] (= value (run expr))
1.0 "1 ^ 0"
4.0 "2^2 "
-9.0 "-3^2 "
9.0 "(-3)^2 "
27.0 " 3^ 3"
0.125 " 2^ -3"
512.0 "2 ^ 3 ^ 2"
256.0 "4.000 ^ 4.0"
2.0 "4^0.5"
0.1 "100^(-0.5)"
125.0 "25^(3/2)"
4096.0 "200% ^ 12"))
(testing "functions"
(are [value expr] (= value (run expr))
2.0 "sqrt( 4 )"
3.0 "abs( 3 )"
3.0 "abs( -3 )"
1.0 "cos( 0 * 1 )"
0.0 "sin( 1 -1 )"
0.0 "atan(tan(0))"
@@ -101,14 +126,9 @@
0.0 "acos(cos(0))"
5.0 "2 * log(10) + 3"
1.0 "-2 * log(10) + 3"
10.0 "ln(1) + 10"))
(testing "avoiding rounding errors"
(are [value expr] (= value (run expr))
3.3 "1.1 + 2.2"
2.2 "3.3 - 1.1"
0.0001 "1/10000"
1e-7 "1/10000000"
)))
10.0 "ln(1) + 10"
1.0 "exp(0)"
2.0 "ln(exp(2))")))
(deftest variables
(testing "variables can be remembered"
@@ -116,7 +136,8 @@
(calc/eval env (calc/parse expr))
(= final-env (into {} (for [[k v] @env] [k (convert-bigNum v)]))))
{"a" 1} "a = 1"
{"a" -1} "a = -1"
{"a" -1} "a = -1"
{"k9" 27} "k9 = 27"
{"variable" 1} "variable = 1 + 0 * 2"
{"x" 1} "x= 2 * 1 - 1 "
{"y" 4} "y =8 / 4 + 2 * 1 - 25 * 0 / 1"
@@ -128,6 +149,7 @@
(calc/eval env (calc/parse expr))
(= final-env (into {} (for [[k v] @env] [k (convert-bigNum v)]))))
{"a_a" 1} "a_a = 1"
{"_foo" 1} "_foo = 1"
{"x_yy_zzz" 1} "x_yy_zzz= 1"
{"foo_bar_baz" 1} "foo_bar_baz = 1 + -0 * 2"))
(testing "variables can be reused"
@@ -150,15 +172,33 @@
{"a" 2 "b" 2} ["a = 1" "b = a + 1" "a = b"]
{"variable" 1 "x" 0} ["variable = 1 + 0 * 2" "x = log(variable)" "x = variable - 1"])))
(deftest last-value
(testing "last value is set"
(are [values exprs] (let [env (calc/new-env)]
(mapv (fn [expr]
(calc/eval env (calc/parse expr)))
exprs))
[42 126] ["6*7" "last*3"]
[25 5] ["3^2+4^2" "sqrt(last)"]
[6 12] ["2*3" "# a comment" "" " " "last*2"])))
(deftest comments
(testing "comments are ignored"
(are [value expr] (= value (run expr))
nil "# this comment is ignored"
nil " # this comment is ignored "
8.0 "2*4# double 4"
10.0 "2*5 # double 5"
12.0 "2*6 # double 6"
14.0 "2*7 # 99")))
(deftest failure
(testing "expressions that don't match the spec fail"
(are [expr] (calc/failure? (calc/eval (calc/new-env) (calc/parse expr)))
"foo_ ="
"foo__ ="
"oo___ ="
" "
"bar_2 = 2 + 4"
"bar_2a = 3 + 4"
"foo_ = "
"foo__ ="
"foo_3 = a")))
" . "
"_ = 2"
"__ = 4"
"foo_3 = _")))