Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
214 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#reader scribble/reader | ||
#lang racket | ||
(require racket/system racket/gui/base) | ||
(provide latex) | ||
|
||
(define str string-append) | ||
|
||
(define TEMPLATE | ||
@str{\documentclass[a0,landscape]{article} | ||
\usepackage[mathletters]{ucs} | ||
\usepackage[utf8x]{inputenc} | ||
\usepackage{amsmath} | ||
\pagestyle{empty} | ||
\usepackage{breqn} | ||
\begin{document} | ||
\hsize=150mm | ||
\begin{dmath*}[style={\huge}] | ||
~a | ||
\end{dmath*} | ||
\end{document}}) | ||
|
||
(define COMMANDS | ||
@str{/usr/texbin/pdflatex x.tex | ||
/opt/local/bin/convert -density 96x96 x.pdf -trim +repage x.png}) | ||
|
||
(define (latex . strs) | ||
(define latex (make-temporary-file "latex~a" 'directory)) | ||
(define (run) | ||
(parameterize ([current-directory latex] | ||
[current-input-port (open-input-bytes #"")] | ||
[current-output-port (open-output-string)]) | ||
(call-with-output-file* "x.tex" #:exists 'truncate | ||
(lambda (o) (fprintf o TEMPLATE (string-append* strs)))) | ||
(unless (system (regexp-replace #rx"\n+" COMMANDS " \\&\\& ")) | ||
(display (get-output-string (current-output-port)) | ||
(current-error-port)) | ||
(error 'latex | ||
"commands did not run successfully, see above output")) | ||
(make-object image-snip% "x.png"))) | ||
(define (cleanup) (delete-directory/files latex)) | ||
; (display-lines (list latex)) | ||
(dynamic-wind void run cleanup)) | ||
|
||
;; Examples | ||
;@latex{\sum_{i=0}^{\infty}\lambda_i} | ||
;(let ([self @str{\lambda x . x x}]) | ||
; @latex{(@self) (@self)}) | ||
|
||
;;; An example to test breaking lines with various page width | ||
;@latex{ | ||
;x^{20}+20\,x^{19}+190\,x^{18}+1140\,x^{17}+4845\,x^{16}+15504\,x^{ | ||
; 15}+38760\,x^{14}+77520\,x^{13}+125970\,x^{12}+167960\,x^{11}+184756 | ||
; \,x^{10}+167960\,x^9+125970\,x^8+77520\,x^7+38760\,x^6+15504\,x^5+ | ||
; 4845\,x^4+1140\,x^3+190\,x^2+20\,x+1} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
#lang at-exp racket | ||
(require racket/tcp racket/gui/base | ||
(planet jaymccarthy/slideshow-latex/latex2bitmap)) | ||
|
||
;;; | ||
;;; Maxima in Racket | ||
;;; | ||
|
||
;; This module starts an external Maxima process. | ||
;; The function send will send a command to Maxima. | ||
;; The function receive will get the output from Maxima as a list of strings. | ||
;; The various send-* and receive-* functions sends and receives to and from Maxima. | ||
;; The various read-* and display-* functions reads and displays to Racket (DrRacket). | ||
|
||
|
||
;;; Configuration: Change maxima, latex and dvipng paths here. | ||
(define PORT 8087) | ||
(define MAXIMA-PATH "/Applications/Maxima.app/Contents/Resources/maxima.sh") | ||
|
||
(define latex-enabled? #t) ; set to #f to disable latex rendering | ||
(latex-path "/usr/texbin/latex") | ||
(dvipng-path "/usr/texbin/dvipng") | ||
(latex-debug? #f) ; if #t prints errors from LaTeX. | ||
|
||
;;; Parameters | ||
|
||
(define out (make-parameter #f)) ; output port for sending | ||
(define in (make-parameter #f)) ; input port for receiving | ||
|
||
;;; Sending | ||
|
||
(define (send str) | ||
(sync (out)) | ||
(display str (out)) | ||
(flush-output (out))) | ||
|
||
(define (send-command str) | ||
(send str)) | ||
|
||
;; Receiving | ||
|
||
(define (receive-line) | ||
(read-line (in))) | ||
|
||
(define (receive-welcome-message) | ||
; Due to the flag --very-quiet the welcome is | ||
; a single line containg the pid. | ||
(list (receive-line))) | ||
|
||
(define (maybe-receive-line) | ||
(if (sync/timeout 0 (in)) | ||
(receive-line) | ||
#f)) | ||
|
||
(define (receive) | ||
(let ([first-line (receive-line)]) | ||
(let loop ([lines (list first-line)]) | ||
(let ([line (maybe-receive-line)]) | ||
(if line | ||
(loop (cons line lines)) | ||
(reverse lines)))))) | ||
|
||
(define (receive-whitespace) | ||
(let ([c (read-char (in))]) | ||
(when (not (char-whitespace? c)) | ||
(error 'read-whitespace "expected to receive whitespace " c)))) | ||
|
||
;; String utilities | ||
|
||
(define (blank-line? line) | ||
(andmap char-whitespace? (string->list line))) | ||
|
||
(define (labeled-line? line) | ||
(regexp-match #rx"^(\\(.+\\)) (.*)$" line)) | ||
|
||
(define (remove-$$ str) | ||
(second (regexp-match #px"^\\$\\$(.*)\\$\\$" str))) | ||
|
||
(define (string-begins-with-$$? str) | ||
(regexp-match #rx"^\\$\\$.*$" str)) | ||
|
||
(define (string-ends-with-$$? str) | ||
(regexp-match #rx"^.*\\$\\$$" str)) | ||
|
||
(define (maybe-add-$$ str) | ||
(string-append | ||
(if (string-begins-with-$$? str) | ||
"" "$$") | ||
str | ||
(if (string-ends-with-$$? str) | ||
"" "$$"))) | ||
|
||
(define (string-ref-last str) | ||
(if (string=? "" str) | ||
#f | ||
(string-ref str (sub1 (string-length str))))) | ||
|
||
;; List utilies | ||
|
||
(define (remove-last xs) | ||
(if (empty? xs) xs (drop-right xs 1))) | ||
|
||
;; Displaying | ||
|
||
(define (display-line datum) | ||
(display datum) | ||
(newline)) | ||
|
||
(define (display-prompt prompt) | ||
(display prompt) | ||
(display " ")) | ||
|
||
(define (display-output lines) | ||
(unless (empty? lines) | ||
(display-lines | ||
(if (and latex-enabled? (string-begins-with-$$? (first lines))) | ||
(list (latex-lines (remove-last lines))) | ||
lines)))) | ||
|
||
(define (latex-lines lines) | ||
(latex (string-append* lines))) | ||
|
||
(define (latex str) | ||
(parameterize ([latex-preamble "\\usepackage{breqn}"] | ||
[latex-dpi 90]) | ||
(make-object image-snip% | ||
(latex->bitmap | ||
@string-append{\begin{dmath*}[style={\huge}]@str \end{dmath*}})))) | ||
|
||
|
||
;; Reading | ||
|
||
(define (read-command) | ||
(let loop ([lines '()]) | ||
(let ([line (read-line)]) | ||
(if (memv (string-ref-last line) '(#\$ #\;)) | ||
(string-append* (reverse (cons line lines))) | ||
(loop (cons line lines)))))) | ||
|
||
;; REPL | ||
|
||
(define (read-send-receive-loop) | ||
(display-prompt ">") | ||
(send-command (read-command)) | ||
(display-output (receive)) | ||
(newline) | ||
(read-send-receive-loop)) | ||
|
||
|
||
;; Start Maxima and REPL | ||
|
||
(let ([listener (tcp-listen PORT 3 #t)]) | ||
(match-let | ||
([(list pin pout pid perr status) | ||
(process* MAXIMA-PATH "--very-quiet" "-s" (format "~a" PORT))]) | ||
(let-values ([(lin lout) (tcp-accept listener)]) | ||
(parameterize ([in lin] [out pout]) | ||
(receive-welcome-message) | ||
(display "Enter a Maxima command. Terminate a command with either ; or $ .\n") | ||
(read-send-receive-loop))))) |