mirror of
https://github.com/logseq/logseq.git
synced 2026-05-24 12:44:22 +00:00
Merge remote-tracking branch 'upstream/master' into whiteboards
This commit is contained in:
@@ -110,12 +110,10 @@ For help on more options, run `node static/tests.js -h`.
|
||||
|
||||
#### Autorun Tests
|
||||
|
||||
To run tests automatically on file save, run `yarn
|
||||
shadow-cljs watch test --config-merge '{:autorun true}'`. The test output may
|
||||
appear where shadow-cljs was first invoked e.g. where `yarn watch` is running.
|
||||
Specific namespace(s) can be auto run with the `:ns-regexp` option e.g. `npx
|
||||
shadow-cljs watch test --config-merge '{:autorun true :ns-regexp
|
||||
"frontend.util.page-property-test"}'`.
|
||||
To run tests automatically on file save, run `clojure -M:test watch test
|
||||
--config-merge '{:autorun true}'`. Specific namespace(s) can be auto run with
|
||||
the `:ns-regexp` option e.g. `clojure -M:test watch test --config-merge
|
||||
'{:autorun true :ns-regexp "frontend.util.page-property-test"}'`.
|
||||
|
||||
## Logging
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { test } from './fixtures'
|
||||
import { createRandomPage } from './utils'
|
||||
|
||||
|
||||
test('flashcard demo', async ({ page, block }) => {
|
||||
test.skip('flashcard demo', async ({ page, block }) => {
|
||||
await createRandomPage(page)
|
||||
|
||||
await block.mustFill('Why do you add cards? #card #logseq')
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns frontend.extensions.calc
|
||||
(:refer-clojure :exclude [eval])
|
||||
(:require [clojure.edn :as edn]
|
||||
[clojure.string :as str]
|
||||
(:require [clojure.string :as str]
|
||||
[frontend.util :as util]
|
||||
|
||||
[bignumber.js :as bn]
|
||||
@@ -18,6 +17,10 @@
|
||||
#?(:clj (def parse (insta/parser (io/resource "grammar/calc.bnf")))
|
||||
:cljs (defparser parse (rc/inline "grammar/calc.bnf")))
|
||||
|
||||
(def constants {
|
||||
"PI" (bn/BigNumber "3.14159265358979323846")
|
||||
"E" (bn/BigNumber "2.71828182845904523536")})
|
||||
|
||||
(defn exception? [e]
|
||||
#?(:clj (instance? Exception e)
|
||||
:cljs (instance? js/Error e)))
|
||||
@@ -29,28 +32,40 @@
|
||||
|
||||
;; TODO: Set DECIMAL_PLACES https://mikemcl.github.io/bignumber.js/#decimal-places
|
||||
|
||||
(defn factorial [n]
|
||||
(reduce
|
||||
(fn [a b] (.multipliedBy a b))
|
||||
(bn/BigNumber 1)
|
||||
(range 2 (inc n))))
|
||||
|
||||
(defn eval* [env ast]
|
||||
(insta/transform
|
||||
{:number (comp bn/BigNumber #(str/replace % "," ""))
|
||||
:percent (fn percent [a] (-> a (.dividedBy 100.00)))
|
||||
:scientific (comp bn/BigNumber edn/read-string)
|
||||
:scientific bn/BigNumber
|
||||
:mixed-number (fn [whole numerator denominator]
|
||||
(.plus (.dividedBy (bn/BigNumber numerator) denominator) whole))
|
||||
:negterm (fn neg [a] (-> a (.negated)))
|
||||
:expr identity
|
||||
:add (fn add [a b] (-> a (.plus b)))
|
||||
:sub (fn sub [a b] (-> a (.minus b)))
|
||||
:mul (fn mul [a b] (-> a (.multipliedBy b)))
|
||||
:div (fn div [a b] (-> a (.dividedBy b)))
|
||||
:mod (fn mod [a b] (-> a (.modulo 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)))))
|
||||
:factorial (fn fact [a] (if (and (.isInteger a) (.isPositive a) (.isLessThan a 254))
|
||||
(factorial (.toNumber a))
|
||||
(bn/BigNumber 'NaN')))
|
||||
:abs (fn abs [a] (.abs a))
|
||||
:sqrt (fn abs [a] (.sqrt a))
|
||||
:sqrt (fn sqrt [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]
|
||||
:exp (fn exp [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))))
|
||||
@@ -65,13 +80,38 @@
|
||||
:acos (fn acos [a]
|
||||
#?(:clj (java.lang.Math/acos a) :cljs (bn/BigNumber(js/Math.acos a))))
|
||||
:assignment (fn assign! [var val]
|
||||
(swap! env assoc var val)
|
||||
(if (contains? constants var)
|
||||
(throw
|
||||
(ex-info (util/format "Can't redefine constant %s" var) {:var var}))
|
||||
(swap! env assoc var val))
|
||||
val)
|
||||
:toassign str/trim
|
||||
:comment (constantly nil)
|
||||
:digits int
|
||||
:format-fix (fn format [places]
|
||||
(swap! env assoc :mode "fix" :places places)
|
||||
(get @env "last"))
|
||||
:format-sci (fn format [places]
|
||||
(swap! env assoc :mode "sci" :places places)
|
||||
(get @env "last"))
|
||||
:format-frac (fn format [max-denominator]
|
||||
(swap! env dissoc :mode :improper)
|
||||
(swap! env assoc :mode "frac" :max-denominator max-denominator)
|
||||
(get @env "last"))
|
||||
:format-impf (fn format [max-denominator]
|
||||
(swap! env assoc :mode "frac" :max-denominator max-denominator :improper true)
|
||||
(get @env "last"))
|
||||
:format-norm (fn format [precision]
|
||||
(swap! env dissoc :mode :places)
|
||||
(swap! env assoc :precision precision)
|
||||
(get @env "last"))
|
||||
:base (fn base [b]
|
||||
(swap! env assoc :base (str/lower-case b))
|
||||
(get @env "last"))
|
||||
:variable (fn resolve [var]
|
||||
(let [var (str/trim var)]
|
||||
(or (get @env var)
|
||||
(or (get constants var)
|
||||
(get @env var)
|
||||
(throw
|
||||
(ex-info (util/format "Can't find variable %s" var)
|
||||
{:var var})))))}
|
||||
@@ -92,12 +132,86 @@
|
||||
(swap! env assoc "last" val))
|
||||
val)
|
||||
|
||||
(defn can-fix?
|
||||
"Check that number can render without loss of all significant digits,
|
||||
and that the absolute value is less than 1e21."
|
||||
[num places]
|
||||
(or (.isZero num )
|
||||
(let [mag (.abs num)
|
||||
lower-bound (-> (bn/BigNumber 0.5) (.shiftedBy (- places)))
|
||||
upper-bound (bn/BigNumber 1e21)]
|
||||
(and (-> mag (.isGreaterThanOrEqualTo lower-bound))
|
||||
(-> mag (.isLessThan upper-bound))))))
|
||||
|
||||
(defn can-fit?
|
||||
"Check that number can render normally within the given number of digits.
|
||||
Tolerance allows for leading zeros in a decimal fraction."
|
||||
[num digits tolerance]
|
||||
(and (< (.-e num) digits)
|
||||
(.isInteger (.shiftedBy num (+ tolerance digits)))))
|
||||
|
||||
(defn format-base [val base]
|
||||
(let [sign (.-s val)
|
||||
display-val (if (neg-int? sign) (.abs val) val)]
|
||||
(str
|
||||
(when (neg-int? sign) "-")
|
||||
(case base 2 "0b" 8 "0o" 16 "0x")
|
||||
(.toString display-val base))))
|
||||
|
||||
(defn format-fraction [numerator denominator improper]
|
||||
(let [whole (.dividedToIntegerBy numerator denominator)]
|
||||
(if (or improper (.isZero whole))
|
||||
(str numerator "/" denominator )
|
||||
(str whole " "
|
||||
(.abs (.modulo numerator denominator)) "/" denominator))))
|
||||
|
||||
(defn format-normal [env val]
|
||||
(let [precision (or (get @env :precision) 21)
|
||||
display-val (.precision val precision)]
|
||||
(if (can-fit? display-val precision 1)
|
||||
(.toFixed display-val)
|
||||
(.toExponential display-val))))
|
||||
|
||||
(defn format-val [env val]
|
||||
(if (instance? bn/BigNumber val)
|
||||
(let [mode (get @env :mode)
|
||||
base (get @env :base)
|
||||
places (get @env :places)]
|
||||
(cond
|
||||
(= base "hex")
|
||||
(format-base val 16)
|
||||
(= base "oct")
|
||||
(format-base val 8)
|
||||
(= base "bin")
|
||||
(format-base val 2)
|
||||
|
||||
(= mode "fix")
|
||||
(if (can-fix? val places)
|
||||
(.toFixed val places)
|
||||
(.toExponential val places))
|
||||
(= mode "sci")
|
||||
(.toExponential val places)
|
||||
(= mode "frac")
|
||||
(let [max-denominator (or (get @env :max-denominator) 4095)
|
||||
improper (get @env :improper)
|
||||
[numerator denominator] (.toFraction val max-denominator)
|
||||
delta (.minus (.dividedBy numerator denominator) val)]
|
||||
(if (or (.isZero delta) (< (.-e delta) -16))
|
||||
(if (> denominator 1)
|
||||
(format-fraction numerator denominator improper)
|
||||
(format-normal env numerator))
|
||||
(format-normal env val)))
|
||||
|
||||
:else
|
||||
(format-normal env val)))
|
||||
val))
|
||||
|
||||
(defn eval-lines [s]
|
||||
{:pre [(string? s)]}
|
||||
(let [env (new-env)]
|
||||
(mapv (fn [line]
|
||||
(when-not (str/blank? line)
|
||||
(assign-last-value env (eval env (parse line)))))
|
||||
(format-val env (assign-last-value env (eval env (parse line))))))
|
||||
(str/split-lines s))))
|
||||
|
||||
;; ======================================================================
|
||||
|
||||
@@ -1252,7 +1252,8 @@
|
||||
|
||||
;; if different direction, keep clear until one left
|
||||
(state/selection?)
|
||||
(clear-last-selected-block!)))
|
||||
(clear-last-selected-block!))
|
||||
nil)
|
||||
|
||||
(defn on-select-block
|
||||
[direction]
|
||||
@@ -3053,7 +3054,8 @@
|
||||
(select-up-down direction)
|
||||
|
||||
:else
|
||||
(select-first-last direction)))))
|
||||
(select-first-last direction)))
|
||||
nil))
|
||||
|
||||
(defn shortcut-select-up-down [direction]
|
||||
(fn [e]
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<start> = assignment | expr | comment
|
||||
expr = add-sub comment
|
||||
<start> = assignment | expr | comment | directive
|
||||
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-div> = pow-term | mul | div | mod
|
||||
mul = mul-div <'*'> pow-term
|
||||
div = mul-div <'/'> pow-term
|
||||
<pow-term> = pow | term
|
||||
mod = mul-div <'mod'> pow-term
|
||||
<pow-term> = pow | factorial | term
|
||||
pow = posterm <'^'> pow-term
|
||||
factorial = posterm <'!'> <#'\s*'>
|
||||
<function> = log | ln | exp | sqrt | abs | sin | cos | tan | acos | asin | atan
|
||||
log = <#'\s*'> <'log('> expr <')'> <#'\s*'>
|
||||
ln = <#'\s*'> <'ln('> expr <')'> <#'\s*'>
|
||||
@@ -21,12 +23,30 @@ tan = <#'\s*'> <'tan('> expr <')'> <#'\s*'>
|
||||
atan = <#'\s*'> <'atan('> expr <')'> <#'\s*'>
|
||||
acos = <#'\s*'> <'acos('> expr <')'> <#'\s*'>
|
||||
asin = <#'\s*'> <'asin('> expr <')'> <#'\s*'>
|
||||
<posterm> = function | percent | scientific | number | variable | <#'\s*'> <'('> expr <')'> <#'\s*'>
|
||||
negterm = <#'\s*'> <'-'> posterm | <#'\s*'> <'-'> pow
|
||||
<posterm> = function | percent | scientific | number | mixed-number | variable | <#'\s*'> <'('> expr <')'> <#'\s*'>
|
||||
negterm = <#'\s*'> <'-'> ( posterm | pow | factorial )
|
||||
<term> = negterm | posterm
|
||||
scientific = #'\s*[0-9]*\.?[0-9]+(e|E)[\-\+]?[0-9]+()\s*'
|
||||
number = #'\s*(\d+(,\d+)*(\.\d*)?|\d*\.\d+)\s*'
|
||||
number = decimal-number | hexadecimal-number | octal-number | binary-number
|
||||
<decimal-number> = #'\s*(\d+(,\d+)*(\.\d*)?|\d*\.\d+)\s*'
|
||||
<hexadecimal-number> = #'\s*0x([0-9a-fA-F]+(,[0-9a-fA-F]+)*(\.[0-9a-fA-F]*)?|[0-9a-fA-F]*\.[0-9a-fA-F]+)\s*'
|
||||
<octal-number> = #'\s*0o([0-7]+(,[0-7]+)*(\.[0-7]*)?|[0-7]*\.[0-7]+)\s*'
|
||||
<binary-number> = #'\s*0b([01]+(,[01]+)*(\.[01]*)?|[01]*\.[01]+)\s*'
|
||||
mixed-number = <#'\s*'> digits <#'\s+'> digits <'/'> digits <#'\s*'>
|
||||
percent = number <'%'> <#'\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
|
||||
assignment = toassign <#'\s*'> <'='> <#'\s*'> expr
|
||||
<directive> = <#'\s*\:'> (format | base) <#'\s*'> [comment]
|
||||
<format> = <#'(format|fmt)\s+'> ( format-fix | format-sci | format-norm | format-frac | format-impf )
|
||||
format-fix = <#'(?i)fix(ed)?\s*'> digits
|
||||
format-sci = <#'(?i)sci(entific)?\s*'> [digits]
|
||||
format-norm = <#'(?i)norm(al)?\s*'> [digits]
|
||||
format-frac = <#'(?i)frac(tions?)?\s*'> [digits]
|
||||
format-impf = <#'(?i)imp(roper)?\s*'> [digits]
|
||||
base = base-hex | base-dec | base-oct | base-bin
|
||||
<base-hex> = #'(?i)hex' <#'(?i)(adecimal)?'>
|
||||
<base-dec> = #'(?i)dec' <#'(?i)(imal)?'>
|
||||
<base-oct> = #'(?i)oct' <#'(?i)(al)?'>
|
||||
<base-bin> = #'(?i)bin' <#'(?i)(ary)?'>
|
||||
digits = #'\d+'
|
||||
@@ -1,11 +1,11 @@
|
||||
(ns frontend.extensions.calc-test
|
||||
(:require [clojure.test :as test :refer [are deftest testing]]
|
||||
[clojure.string :as str]
|
||||
[clojure.edn :as edn]
|
||||
[frontend.extensions.calc :as calc]))
|
||||
|
||||
(defn convert-bigNum [b]
|
||||
(edn/read-string (str b))
|
||||
)
|
||||
(edn/read-string (str b)))
|
||||
|
||||
(defn run [expr]
|
||||
{:pre [(string? expr)]}
|
||||
@@ -130,6 +130,23 @@
|
||||
1.0 "exp(0)"
|
||||
2.0 "ln(exp(2))")))
|
||||
|
||||
(deftest additional-operators
|
||||
(testing "mod"
|
||||
(are [value expr] (= value (run expr))
|
||||
0.0 "1 mod 1"
|
||||
1.0 "7 mod 3"
|
||||
3.0 "7 mod 4"
|
||||
0.5 "4.5 mod 2"
|
||||
-3.0 "-7 mod 4"))
|
||||
(testing "factorial"
|
||||
(are [value expr] (= value (run expr))
|
||||
1.0 "0!"
|
||||
1.0 "1!"
|
||||
6.0 "3.0!"
|
||||
-120.0 "-5!"
|
||||
124.0 "(2+3)!+4"
|
||||
240.0 "10 * 4!")))
|
||||
|
||||
(deftest variables
|
||||
(testing "variables can be remembered"
|
||||
(are [final-env expr] (let [env (calc/new-env)]
|
||||
@@ -174,13 +191,78 @@
|
||||
|
||||
(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"])))
|
||||
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
|
||||
["42" "126"] ["6*7" "last*3"]
|
||||
["25" "5"] ["3^2+4^2" "sqrt(last)"]
|
||||
["6" nil nil nil "12"] ["2*3" "# a comment" "" " " "last*2"])))
|
||||
|
||||
(deftest formatting
|
||||
(testing "display normal"
|
||||
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
|
||||
[nil "1000000"] [":format norm" "1e6" ]
|
||||
[nil "1000000"] [":format norm 7" "1e6"]
|
||||
[nil "1e+6"] [":format norm 6" "1e6"]
|
||||
[nil "3.14"] [":format norm 3" "PI"]
|
||||
[nil "3"] [":format norm 1" "E"]
|
||||
[nil "0.000123"] [":format norm 5" "0.000123"]
|
||||
[nil "1.23e-4"] [":format norm 4" "0.000123"]
|
||||
[nil "123400000"] [":format normal 9" "1.234e8"]
|
||||
[nil "1.234e+8"] [":format normal 8" "1.234e8"]))
|
||||
(testing "display fixed"
|
||||
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
|
||||
[nil "0.123450"] [":format fix 6" "0.12345"]
|
||||
[nil "0.1235"] [":format fix 4" "0.12345"]
|
||||
[nil "2.7183"] [":format fixed 4" "E"]
|
||||
[nil "0.001"] [":format fix 3" "0.0005"]
|
||||
[nil "4.000e-4"] [":format fix 3" "0.0004"]
|
||||
[nil "1.00e+21"] [":format fixed 2" "1e21+0.1"]))
|
||||
(testing "display scientific"
|
||||
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
|
||||
[nil "1e+6"] [":format sci" "1e6"]
|
||||
[nil "3.142e+0"] [":format sci 3" "PI"]
|
||||
[nil "3.14e+2"] [":format scientific" "3.14*10^2"])))
|
||||
|
||||
(deftest fractions
|
||||
(testing "mixed numbers"
|
||||
(are [value expr] (= value (run expr))
|
||||
0 "0 0/1"
|
||||
1 "0 1/1"
|
||||
1 "1 0/1"
|
||||
2.5 "2 1/2"
|
||||
2.5 "2 1/2"
|
||||
-4.28 "-4 7/25"
|
||||
2.00101 "2 101/100000"
|
||||
-99.2 "-99 8/40"))
|
||||
(testing "display fractions"
|
||||
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
|
||||
[nil "4 3/8"] [":format frac" "4.375"]
|
||||
[nil "-7 1/4"] [":format fraction" "-7.25"]
|
||||
[nil "2"] [":format fractions" "19/20 + 1 1/20"]
|
||||
[nil "-2"] [":format frac" "19/17 - 3 2/17"]
|
||||
[nil "3.14157"] [":format frac" "3.14157"]
|
||||
[nil "3 14157/100000"] [":format frac 100000" "3.14157"]))
|
||||
(testing "display improper fractions"
|
||||
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
|
||||
[nil "35/8"] [":format improper" "4.375"]
|
||||
[nil "-29/4"] [":format imp" "-7.25"]
|
||||
[nil "3.14157"] [":format improper" "3.14157" ]
|
||||
[nil "314157/100000"] [":format imp 100000" "3.14157"])))
|
||||
|
||||
(deftest base-conversion
|
||||
(testing "mixed base input"
|
||||
(are [value expr] (= value (run expr))
|
||||
255.0 "0xff"
|
||||
511.0 "0x0A + 0xF5 + 0x100"
|
||||
83.0 "0o123"
|
||||
324.0 "0x100 + 0o100 + 0b100"
|
||||
32.0 "0b100 * 0b1000"))
|
||||
(testing "mixed base output"
|
||||
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
|
||||
["12345" "0x3039"] ["12345" ":hex"]
|
||||
["12345" "0o30071"] ["12345" ":oct"]
|
||||
["12345" "0b11000000111001"]["12345" ":bin"]
|
||||
[nil "0b100000000"] [":bin" "0b10000 * 0b10000"]
|
||||
[nil "-0xff"] [":hex" "-255"])))
|
||||
|
||||
(deftest comments
|
||||
(testing "comments are ignored"
|
||||
@@ -201,4 +283,5 @@
|
||||
" . "
|
||||
"_ = 2"
|
||||
"__ = 4"
|
||||
"PI = 3.14"
|
||||
"foo_3 = _")))
|
||||
|
||||
Reference in New Issue
Block a user