Code Monkey home page Code Monkey logo

literate-calc-mode.el's Introduction

Literate Calc Mode

https://melpa.org/packages/literate-calc-mode-badge.svg

Literate programming for M-x calc. There is an announcement blog post.

Displays inline results for calculations, supports variables and updates as you type (if you want). Also works in your favourite markup mode.

./scrot.png

Installing

Simply grab it from MELPA.

(use-package literate-calc-mode
  :ensure t)
(straight-use-package 'literate-calc-mode)

package.el

Ensure you have MELPA available.

M-x package-install, select literate-calc-mode.

Manual

Just fetch literate-calc-mode.el, save it somewhere and load it into Emacs.

Configuration

There is a M-x customize group named after the mode which contains the following options:

literate-calc-mode-idle-timeHow long to wait after typing to recalculate results (buffer-local)
literate-calc-mode-inhibit-line-functionsHook functions called for each line to test whether to inhibit calculation (buffer-local)
literate-calc-mode-radixDefault radix/base for results (buffer-local)
literate-calc-max-buffer-sizeMaximum buffer size to activate the minor mode
literate-calc-usimplify-resultsApply usimplify to all results implicitly (buffer-local)
literate-calc-equalsThe string used to indicate a result (default: ” => “)
literate-calc-mode-result-faceThe face used when inserting results into the buffer
literate-calc-mode-identifier-faceThe face used to highlight variables during assignment

The idle time prevents lag due to constant recalculation in the middle of typing, defaulting to 1 second.

These are the available inhibitors, which are all enabled by default:

literate-calc-mode-inhibit-in-src-blocks
Prevents evaluation inside org-mode src blocks
literate-calc-mode-inhibit-in-latex
Prevents evaluation inside org-mode LaTeX fragments

Of course you can also just setq / setq-default the options directly.

Calc Configuration

Because LCM uses Emacs calc under the hood, a lot of configuration options for calc also affect LCM operation.

An interesting one is calc-multiplication-has-precedence, which when non-nil means that multiplication will have higher precedence than division, which can lead to surprising results.

Use

There is both a major literate-calc-mode and a minor literate-calc-minor-mode. The major mode does some basic syntax highlighting, while the minor mode only evaluates all calc statements while typing.

The minor mode works quite well with org-/markdown mode or other markup language major modes.

There are also some functions which can be called without any mode being active:

M-x literate-calc-eval-lineEvaluates a single line
M-x literate-calc-eval-regionEvaluates within the selected region
M-x literate-calc-eval-bufferEvaluates the whole buffer
M-x literate-calc-insert-resultsEvaluates the whole buffer and inserts results
M-x literate-calc-clear-overlaysRemoves all overlays and clears variables
M-x literate-calc-remove-resultsRemoves all results and clears variables
M-x literate-calc-set-radixSets the radix/base output for the current buffer

Using Units

You can simply append units to your values like so:

Flour = 500g => Flour: 500 g

Unit conversion (and other complex functions) can be used by invoking the matching Algebraic Function.

= usimplify(1m + 3mm) => 1.003 m

You can also use unknown mathematical symbols:

= x*2 + x-3 => 3 x - 3

Evaluation in Org

Org-mode source blocks can be evaluated (C-c C-c by default).

If :results is set to value, which is the default, a block returns its last result. If :results is set to output, it will return the entire block, annotated with results.

Local variables can be defined in header arguments as :var a=38 b=4.

Changing radix/base

You can change the literate-calc-mode-radix custom variable to set the default base for number output globally for all literate-calc-mode buffers, but it’s also possible to change the output radix of the current buffer by calling the interactive function literate-calc-set-radix in your desired buffer. For example, M-x literate-calc-set-radix 16 will display results with base 16 (hex).

Example output with radix set to 16:

a0 = 2#11001100 => a0: 16#CC
a1 = 2#11110000 => a1: 16#F0
= and(a0, a1) => 16#C0

Full Example

This is a literate calc file.

Lines without "=" are ignored.

All results starting with "=>" are an overlay generated by
literate-calc-mode. That means they are displayed in Emacs, but not
actually in the buffer/file contents.

We can calculate a value like so:

= 2 + 2 => 4

If there is any string on the left hand side, it becomes a bound
variable.

Pi = 3.14159 => Pi: 3.14159

We can use this variable below the definiton.

Tau = Pi * 2 => Tau: 6.28318

Results are calculated using Emacs' own calc, so you can use formulas
as well.

= round(Pi, 2) => 3.14

Later bindings shadow earlier ones:

Pi = 3 => Pi: 3

= Pi => 3

Variable names can have spaces as well:

Monthly Expenses = 500 => Monthly Expenses: 500

Monthly Income = 1000 => Monthly Income: 1000

Annual Savings = 12 * (Monthly Income - Monthly Expenses) => Annual Savings: 6000

All values are recalculated on every update in a spreadsheet-like
fashion.

Calc also has a lot of advanced features, like arrays:

Numbers = [1 2 3] => Numbers: [1, 2, 3]

= 3 Numbers => [3, 6, 9]

Roadmap

There are some additional features I’m currently thinking about.

Semantic Highlighting

One of the original inspirations was Tydlig, which does similar things, but also has semantic highlighting. That means, variables are highlighted in different colours, but always the same one for a given variable, so that you can see where it’s used at a glance.

I might steal some code from rainbow-identifiers, which is one of the shorter existing implementations around, and adapt that to our needs.

literate-calc-mode.el's People

Contributors

artenator avatar chrisbarrett avatar dme avatar sulami avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

literate-calc-mode.el's Issues

Debugger entered--Lisp error: (wrong-type-argument timerp nil)

call `literate-calc-mode' again after enable it will cause this error
This small patch fix it.

@@ -287,7 +287,8 @@ The exact timeout is determined by `literate-calc-mode-idle-time'."
 
 (defun literate-calc--exit ()
   "Clean up hooks & overlays."
-  (cancel-timer literate-calc--idle-timer)
+  (when literate-calc--idle-timer
+	(cancel-timer literate-calc--idle-timer))
   (remove-hook 'after-change-functions #'literate-calc--async-eval-buffer t)
   (literate-calc-clear-overlays))

Enhancements

Hi,

Nice package.

Here is a function you might want to include :

(defun literate-calc-mode-inhibit-in-latex ()
  "Return non-nil if point is in a latex fragment or environment."
  (and (derived-mode-p #'org-mode)
       (memq (org-element-type (org-element-context))
             '(latex-fragment latex-environment))))

Otherwise, literate-calc-minor-mode interacts with latex fragments and environments.

Also, could it be possible to add a literate-calc-eval-region interactive function ?

Regards

Warning during byte compiling

I'm trying to package this for guix but guix won't let me package this if it throws a warning during byte compiling.

The warning is this:

In literate-calc-insert-results:
literate-calc-mode.el:171:29:Warning: reference to free variable
    ‘literate-calc-minor-mode’

Moving the definition of literate-calc-minor-mode above this line makes the warning go away.

This is on Emacs 26.3 if that makes an difference.

Vectors, lists and multiline summations

This package is the coolest! Ever since hearing about a mac app Soulver, I've yearned for a free literate calculator for linux. So thank you for having the vision of combining the powerhouse that is calc and making a well-working implementation. :)

I immediately made this helper function to have quick access to a quick scribble when needed.

  (defun pop-calculator ()
    (interactive)
    (switch-to-buffer (get-buffer-create "*literate-calc*"))
    (literate-calc-mode))

But now to the question. Please keep in mind that I am not a calc expert so I am partly thinking about a feature request but also like to hear about what calc the backend can do here without any further development.

I like making lists and summing them up. Traditionally a job for org tables or perhaps the ses-mode, I like the fluency of a list within free text.

But understandably we don't have a multiline support so we're left with these approaches:

a = 10 => a: 10
a = a + 10 => a: 20
a = a + 20 => a: 40

b = [1 2 4] => b: [1, 2, 4]

= a => 40
= vsum(b) => 7

Perhaps I just don't necessarily like the repeated use of the variable name. += would be an obvious idea to consider. I thought about other kinds of multiline supports for vectors but inline comments are valuable to me and now things would definitely get too complex and unpredictable.

Maybe the purpose of this ticket is just to say thanks for a great library.

Comparison with embedded calc mode?

I think it would be useful to compare this mode with embedded calc mode, in the README and perhaps explain why you would use this instead. I think one obvious difference might be support for spaces in variable names.

(calc) Embedded Mode

Use cases not yet fulfilled by literate-calc-mode that somehow relate to exporting

Here is a list of use cases loosely related to exporting.

  • Copying the result of a calculation
  • Showing how a result was computed to other people that do not have literate-calc-mode. Two possible export methods:
    • Sharing the literate-calc-mode file with the results
    • Putting the literate-calc-mode file with the results in the clipboard
  • Surround computation by more context written in an existing format, like markdown or org-mode

Lisp error during org export

If I try to export an org source code block with literate-calc-mode and I happen to have a variable in it, I get an lisp error during htmlization.

For example, if I export this org file

#+begin_src literate-calc
Pi = 3.14159
#+end_src

I get:

Lisp error: (args-out-of-range "Pi " 0 12)

Btw. I was able to workaround this by setting literate-calc-font-lock-defaults to nil:

# -*- literate-calc-font-lock-defaults: nil -*-
#+begin_src literate-calc
Pi = 3.14159
#+end_src

The calculation oder is wrong

Like this:

2

Multiplication and division have the same calculation priotiry, so it should gives 16 even without explicit parentheses, but it seems multiplications are calculated first then the division...

Thousand Separator

This is an amazing package, thank you for the great idea and implementation. For readability, I think it would be great if the package showed the result with thousand separator. Would you consider this improvement?

Thank you

Significant Lagging when used in Org minor-mode

I truly love this little thing. I wanted it to hook with org-mode so I added this little hook.
(add-hook 'org-mode-hook 'literate-calc-minor-mode) but this causes org-mode buffer files to be extremely lagging. In fact, it is lagging each time I enabled the minor-mode. Anyone else experiencing this issue? Is this expected?

Thanks for this great work.

Custom variable to set default Radix format, ability to change buffer local radix output

Hi,

Sometimes when doing binary arithmetic, it is useful to be able to see the output formatted in different bases, such as base 16 or base 2.

I have implemented this feature into literate-calc-mode locally, and I was wondering if you would be open to such a feature. If so, I can make a PR!

Summary:

  • New custom literate-calc-mode-radix with a default value of 10
    • This value is passed into calc-eval for the option calc-number-radix
  • New interactive function literate-calc-set-radix, which sets the radix of the current buffer and reruns 'literate-calc--async-eval-buffer

Example with radix set to 2:
image

Example with radix set to 16
image

Possible feature: Anonymous calculation

Potential Problem

Sometimes, when writing a literate-calc-mode file, I want to have the computer do a quick calculation for me. That calculation is not to stay in the final document.

pizzaPrice = 10 euros
deliveryPrice = 2 euros

pizzaPrice + (deliveryPrice / 3)

That last line would be an example of this "quick calculation". Problem: the program doesn't display the result of this line. I need to assign the result of this calculation to a temporary variable in order to get the result (before immediately deleting it).

Possible solutions

  • Display the result for any calculation in the file
  • Display the result any line that ends with a specific set of character, for instance "=>"

function problem

Hi,

tried to calculate the Greatest Common Divisor of two integers, and noticed this:

image

when I remove the comment from the third line:

image

seems to be some parsing bug, can you please confirm?

Suggestion: add an extension point to inhibit eval line

Hey there!

I'm using this with org mode and I'd like to avoid matching lines that are in certain illegal contexts, like org source blocks. It's easy to hack around this with advice but it would be nice to add an extension point.

What do you think about adding a custom hook that gets called for each line to test whether to inhibit evaluation? You could ship with a default implementation too, which would improve the out-of-the-box experience. Happy to whip up a PR to sketch this out.

Polymode for literate-calc

I was attempting to create a polymode for literate-calc so I can embed it into any mode without having to use the minor mode and without the "session" leaking across.

I ran into some issues and posted in the Polymode github: polymode/polymode#313, in case you have any insight into how I can do this.

[Feature Request] Have => trigger a calculation parse from previous = sign even if spans multiple lines

First off, thank you soooooo much for making this!!

I was a huge user of Calca previously and basically, this if you hadn't have built this I would have had to myself. I've been testing the minor mode today and love it. I am taking a look at your code later to figure out how you did it. =] This rocks. (only tried it with my old markdown Calca files so far. Also, supporting most of the features in Calca would be baller if you need some extra roadmap ideas.)

One thing that would be amazing in order to support more ordered, thoughtful files would be to support the => as an trigger on calculaton on the last previous variable you've defined a formula for (ie the last thing_to_calculate = this + that.+ other things) even if it spans multiple lines.).
Eg.

Food            = 150 * Months * Days
                => 36,000 (derived from literate-calc package)

instead of

Food            = 150 * Months * Days => Food: 36,000. (derived)

I'd also suggest that that would also work better than having every line provide a solution to each declaration (right now I have lines that look like this:

Months         		= 8. => Months: 8
Days			= 30 => Days: 30
Working Days	        = 20 => Working Days: 20

from ol Calca formulas.

But just wanted to say thank you so much for your work on this. I had this as a project I really needed to get to towards the end of the year, so am ecstatic someone has beat me to it. \o/

function names collide with variable names

Variable names that are sub-strings of functions destroy the functions.

image

= abs(-2)
ab = 3
= abs(-2)

I'd suggest an option to disable the short writing that omits the * character.

I'm not sure if the setting should be enabled or disabled by default:

  • default omitting enabled: formulas omiting the char don't work as expected any more, but the error is obvious and easily fixed by adding the `*-
  • default omitting disabled: formulas work, but functions fail in odd looking ways. Harder to "debug" as a user.

Anyways, no critical bug. It's easily detected and worked around.

Lists

Could it work with lists?
For example:

- a = 10
- b = 20
- = a+b

Thanks for your nice package.

Fix for #15 broke variable names that contain identifiers

fb39084 introduced a fix for #15 but seems to have broken the package by being too restrictive in what variable name we can use.

Example test that fails (after the fix but worked before) to show the issue:

;; FAIL (seems to be because of year in the name)
(ert-deftest literate-calc-mode-test/overlapping-names-2-test ()
  (with-temp-buffer
    (literate-calc-mode)
    (insert "yearlyfoo = 25\nbar=yearlyfoo * 2")
    (literate-calc-insert-results)
    (should (equal "yearlyfoo = 25 => yearlyfoo: 25\nbar=yearlyfoo * 2 => bar: 50"
                   (buffer-string)))))

This prevent using any identifier (like year) as part of variable names, which is a problem that I have encountered frequently trying to use literate-calc-mode, so I reverted my local version to before the fix for #15.

Is there a way to always simplify units?

Hi! Thank you so much for Literate Calc Mode. It's very cool!

I started to use it to calculate service fees for my clients. Something like:

weeks = 5 days => weeks: 5 days

Contract duration = 5 weeks => Contract duration: 25 days
Time off = 3 days => Time off: 3 days
Work time = Contract duration - Time off => Work time: 22 days
Cost = 1000 EUR / days => Cost: 1,000 EUR / days
Fee = Cost * Work time => Fee: 22,000 EUR days / days

It's really nice to use multiple words for variables. Makes it much more suitable for non-technical recepients of my invoices. However the bottom line is not so nice when it comes to units (EUR days / days). It's possible to wrap it in usimplify, but then the calculation is not so friendly for non-programmers:

Fee = usimplify (Cost * Work time) => Fee: 22,000 EUR

Is there a way to always apply usimplify to the results? I tried to set the calc-simplify-mode to units, but it doesn't seem to have any effect.

(setq-local calc-simplify-mode 'units)

Related issue: #27

Anyway, thank you so much!

Bug in literate-calc-minor-mode save-match-data

I tried to turn on literate-calc-minor-mode in org-mode files and found that it broke org-capture.
When I try to capture, I would get the error message "Match data clobbered by buffer modification hooks."

The problem appears to be a failure to wrap the body of your literate-calc--eval-buffer in save-match-data, as in this similar issue:

https://emacs.stackexchange.com/questions/38800/match-data-clobbered-by-buffer-modification-hooks

The problem went away when I removed literate-calc-minor-mode from my org-mode hook.

Very nice facility, by the way. Thanks for contributing!

Incorrect handling of complex units

Complex units are handled incorrectly, for example:

  Weight = 1.3oz/yd^2
  Area = 2m^2
  Total Weight = Weight * Area

Should result in 3.109 oz, but actual output is 0.2166 oz / (d^2 m^2).

Note that the initial value is already incorrect, the first line shows => Weight: 0.4333 oz/d^2.

As comparison, (calc-eval "1.3oz/yd^2") results in 1.3 oz / yd^2, and (calc-eval "(1.3oz/yd^2) * (2m^2)") in 2.6 oz m^2 / yd^2, which is correct.

Units convertion

How can we convert units?
I've done it using usimplify like in the readme:

Surface = 5000000 mm^2
=usimplify(1 m^2 + Surface - 1 m^2) => 5 m^2

Is there a better way?

Best regards

Wishes Really

  1. After an insert into buffer, would be nice to have a command to clear the results (i.e., the => stuff) and allow revision, and if a region is active limit the clearing to the region.

  2. Unless you're constrained by calc, allow variable names to have digits in them, e.g., Price1, Price2, and perhaps underscores, Price_1 and Price_2

  3. Allow variables from lines with inserted results to continue to participate in calculations, now they seem to be "deactivated."

  4. Real kick-ass addition to Emacs, many thanks Sulami!

org-todo: Match data clobbered by buffer modification hooks

Hi this package seems awesome but I've run into one problem.

I have (setq org-log-done 'time) in my config and when I have literate-calc-minor-mode enabled then marking an org TODO item done gives the following message:

org-todo: Match data clobbered by buffer modification hooks

and no timestamp is inserted.

Sequential multiplication not working?

Hello! Firstly, thanks for literate-calc-mode! It's a great package!

Anyway, I've been having an issue with the following:

Gas Range = [ 30.00 .. 45.00 ) => Gas Range: [30. .. 45.)
Gas Spending Per Month = Gas Range * 2 => Gas Spending Per Month: [60. .. 90.)
Gas Spending Yearly = Gas Spending Per Month * 12 => Gas Spending Yearly: 12 Gas Spending Per Month

Not sure why the following is happening on the third line. Some info:

Where I'm using this: Org-mode

literate-calc-mode verions: 20230612.2332

Emacs version: 30.0.50

`literate-calc-insert-results` insert partially evaluated results

Hi @sulami,

Thanks for writing this package! I'm using it to do end of the month finance stuff with my girlfriend 🙂

I noticed that literate-calc-insert-result doesn't insert the fully evaluated results, which are shown in the overlays. Here is an example:

a = 1
b = 1
c = a + b
d = b + c
e = c + d

The overlay shows fully evaluated, concrete results:
image

while literate-calc-insert-result shows:
image

I'm using Emacs 28.0.50 on macOS and literate-calc-mode 20200525.1416.

Please let me know if you need more details.

Exporting results

Hi. Thanks for your nice package. It is amusing.

I would like export its results to make reports using the calcs, is it possible? Not all operations, but some of them, the results I find relevant.

Best regards

Don't calc for org =emphasis= syntax

Stricter syntax requirements would be good to avoid treating =emphasis= highlights as calc statements. I see

treat =emphasis= highlights `=> treat: emphasis`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.