scope/internal/cards/calc.go

157 lines
3.7 KiB
Go
Raw Normal View History

2021-12-08 17:24:05 +00:00
package cards
import (
"fmt"
"html/template"
"regexp"
"strings"
)
const calcExtraHead = `
<link rel="stylesheet" href="/static/katex.min.css">
<script defer src="/static/katex.min.js"></script>
<script src="/static/nerdamer.core.js"></script>
<script src="/static/Algebra.js"></script>
<script src="/static/Calculus.js"></script>
<script src="/static/Solve.js"></script>`
const solveRenderScript = `
<div id="calc-content" class="subtitle mx-2 my-0"></div>
<script>
window.onload = () => {
latex = nerdamer.convertToLaTeX(nerdamer('%s').toString())
katex.render(latex, document.getElementById('calc-content'))
}
</script>`
func init() {
// Register calc card
Register("calc", 0, NewCalcCard)
}
// CalcCard represents a calculation card
type CalcCard struct {
query string
useFunc bool
function string
args []string
expression string
}
// NewCalcCard is a NewCardFunc that creates a new CalcCard
func NewCalcCard(query, _ string) Card {
return &CalcCard{query: query, useFunc: true}
}
func (cc *CalcCard) Matches() bool {
// If query has solve prefix
if strings.HasPrefix(cc.query, "solve") {
// Set function to solve
cc.function = "solve"
// Compile regex for specifying veriable to solve for
forRgx := regexp.MustCompile(`solve (.+) for (.+)`)
// If query matches regex
if forRgx.MatchString(cc.query) {
// Find furst regex match
matches := forRgx.FindStringSubmatch(cc.query)
// Append function aeguments. First is equation, second variable
cc.args = append(cc.args, matches[1], matches[2])
} else {
// Append function arguments assuming variable is x
cc.args = append(cc.args, cc.StripKey(), "x")
}
return true
}
// If query has integrate prefix
if strings.HasPrefix(cc.query, "integrate") ||
strings.HasPrefix(cc.query, "integral of") ||
strings.HasPrefix(cc.query, "integral") {
// Set function to integrate
cc.function = "integrate"
// Append function arguments
cc.args = append(cc.args, cc.StripKey())
return true
}
// If query has derivative prefix
if strings.HasPrefix(cc.query, "diff") ||
strings.HasPrefix(cc.query, "derive") ||
strings.HasPrefix(cc.query, "differentiate") ||
strings.HasPrefix(cc.query, "derivative of") ||
strings.HasPrefix(cc.query, "derivative") {
// Set function to diff
cc.function = "diff"
// Append function arguments
cc.args = append(cc.args, cc.StripKey())
return true
}
// If query has calculate prefix
if strings.HasPrefix(cc.query, "calculate") {
// This is an expression, so no function needed
cc.useFunc = false
// Set expression to query stripped of keys
cc.expression = cc.StripKey()
return true
}
return false
}
func (cc *CalcCard) StripKey() string {
// Compile regex for words to be removed
trimRgx := regexp.MustCompile(`^(.*?)solve|integrate|integral(?: of)?|diff|differentiate|derivative(?: of)?|derive|calculate(.*)$`)
// Return string with words removed
return trimRgx.ReplaceAllString(cc.query, "${1}${2}")
}
func (cc *CalcCard) Content() template.HTML {
var input string
// If function is being used
if cc.useFunc {
// Set input to formatted function
input = formatFunc(cc.function, cc.args)
} else {
// Set input to expression
input = cc.expression
}
// Return script with given input
return template.HTML(fmt.Sprintf(
solveRenderScript,
input,
))
}
func (cc *CalcCard) Footer() template.HTML {
return ""
}
func (cc *CalcCard) Returned() bool {
return true
}
func (cc *CalcCard) RunQuery() error {
return nil
}
func (cc *CalcCard) Title() string {
return "Calculation"
}
func (cc *CalcCard) Head() template.HTML {
return calcExtraHead
}
func formatFunc(function string, args []string) string {
// Format as function(arg1,arg2...)
return function + "(" + strings.Join(args, ",") + ")"
}