emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/julia-mode f7b8178fbf 11/14: Merge remote-tracking branch


From: ELPA Syncer
Subject: [nongnu] elpa/julia-mode f7b8178fbf 11/14: Merge remote-tracking branch 'upstream/master' into li1-imenu-fixes
Date: Wed, 12 Jul 2023 04:00:20 -0400 (EDT)

branch: elpa/julia-mode
commit f7b8178fbf356909084e88c2653ae93b6c180337
Merge: 180b7fc5b6 adf4029be7
Author: Adam Beckmeyer <adam_gpg@thebeckmeyers.xyz>
Commit: Adam Beckmeyer <adam_gpg@thebeckmeyers.xyz>

    Merge remote-tracking branch 'upstream/master' into li1-imenu-fixes
---
 .github/workflows/CI.yml |  55 +++++++
 CHANGELOG.md             |   2 +
 README.md                |  52 ++++--
 julia-mode-latexsubs.el  | 419 ++++++++++++++++++++++++++++++++++++++++++++---
 julia-mode-tests.el      | 239 ++++++++++++++++++++++++++-
 julia-mode.el            | 307 +++++++++++++++++++---------------
 6 files changed, 898 insertions(+), 176 deletions(-)

diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
new file mode 100644
index 0000000000..b372ea0177
--- /dev/null
+++ b/.github/workflows/CI.yml
@@ -0,0 +1,55 @@
+# uses https://github.com/leotaku/elisp-check for CI and
+# https://github.com/purcell/setup-emacs for Emacs setup
+
+name: check
+
+on:
+  pull_request:
+  push:
+    branches:
+      - master
+      - 'releases/*'
+
+jobs:
+  check:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        emacs_version:
+          - 25.1
+          - 25.2
+          - 25.3
+          - 26.1
+          - 26.2
+          - 26.3
+          - 27.1
+          - 27.2
+        ignore_warnings:
+          - true
+        include:
+          - emacs_version: snapshot
+            ignore_warnings: false
+    steps:
+    - uses: actions/checkout@v2
+    - uses: purcell/setup-emacs@master
+      with:
+        version: ${{ matrix.emacs_version }}
+    - name: Run ert
+      uses: leotaku/elisp-check@master
+      with:
+        check: ert
+        file: 'julia-mode-tests.el'
+        ignore_warnings: ${{ matrix.ignore_warnings }}
+    # - name: Run package-lint # FIXME disabled as failing
+    #   uses: leotaku/elisp-check@master
+    #   with:
+    #     file: "julia-mode.el"
+    #     ignore_warnings: true
+    #     check: package-lint
+    - name: Run byte-compile
+      uses: leotaku/elisp-check@master
+      with:
+        file: "julia-mode.el"
+        ignore_warnings: true
+        check: byte-compile
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 856dabe1b1..5aa25dcd53 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,7 @@
 # Unreleased
 
+- fix indentation of submodule imports
+
 # 0.4
 
 - increase lookback 
([#98](https://github.com/JuliaEditorSupport/julia-emacs/pull/98)), fixes 
[#5](https://github.com/JuliaEditorSupport/julia-emacs/issues/5)
diff --git a/README.md b/README.md
index b1805544c2..2cd68d20d2 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,59 @@
-# Emacs major mode for the julia programming language
+# julia-mode
 
-[![Build 
Status](https://travis-ci.org/JuliaEditorSupport/julia-emacs.svg?branch=master)](https://travis-ci.org/JuliaEditorSupport/julia-emacs)
 
[![MELPA](https://melpa.org/packages/julia-mode-badge.svg)](https://melpa.org/#/julia-mode)
+[![Build 
Status](https://travis-ci.org/JuliaEditorSupport/julia-emacs.svg?branch=master)](https://travis-ci.org/JuliaEditorSupport/julia-emacs)
+
+[Emacs](https://www.gnu.org/software/emacs/) major mode for [the Julia 
programming language](https://julialang.org/).
 
-# Installation
 
-## Installing from MELPA
+## Installation
+
+### Installing from MELPA
 
 Unless you want to develop this package, it is recommended that you use it 
from MELPA:
 
-1. [Enable the MELPA repository](https://melpa.org/#/getting-started).
+1. Enable [the MELPA repository](https://melpa.org/#/getting-started).
 
-2. Add `(require 'julia-mode)` to your Emacs init file.
+2. Enable the package by adding these lines to to your Emacs init file, e.g., 
`~/.emacs`:
 
-## Using the source repository directly
+```elisp
+(package-install 'julia-mode)
+(require 'julia-mode)
+```
 
-Clone this repository, then use
+### Installing from Source
+
+To get the latest version of `julia-mode`, clone this repository and then use:
 
 ```elisp
-(add-to-list 'load-path "path-to-julia-mode")
+(add-to-list 'load-path "<path-to-julia-mode>")
 (require 'julia-mode)
 ```
 
-# Contributing
+## Contributing
 
 Contributions are welcome, in the form of pull requests.
 
-Please
+We do our best to provide feedback within 2 weeks. Feel free bump the PR 
thread with a comment after that.
+
 
-1. add unit tests whenever possible. This may require that functions are 
broken up into an interface and a backend function, then you can test the 
backend one.
+### Submitting Pull Requests
 
-2. add a short summary in the [Unreleased section of the 
CHANGELOG](CHANGELOG.md#unreleased).
+- Do add unit tests whenever possible. Consider breaking functions into an 
interface and a backend function for convenient testing.
 
-3. use the `rx` macro (S-expressions) whenever rewriting existing regular 
expressions or introducing new ones; it keeps the code much more readable.
+- Do add a short summary in the *Unreleased* section of the 
[CHANGELOG](CHANGELOG.md#unreleased).
 
-We do our best to provide feedback within 2 weeks, feel free to bump in a 
comment after that.
+- Do use the `rx` macro (S-expressions) whenever rewriting regular expressions 
or introducing new ones. This keeps the code much more readable.
+
+
+### Working With Tests
+
+It's easy to add new 
[ERT](https://www.gnu.org/software/emacs/manual/html_node/ert/index.html) tests 
to the `julia-mode` test suite.
+
+You only need to prepare a new `ert-deftest` definition in 
`julia-mode-tests.el`.
+
+You can run the test suite from the command line with:
+
+```
+emacs -batch -L . -l ert -l julia-mode-tests.el -f  
ert-run-tests-batch-and-exit
+```
diff --git a/julia-mode-latexsubs.el b/julia-mode-latexsubs.el
index 38eb8e09ab..a85aae028a 100644
--- a/julia-mode-latexsubs.el
+++ b/julia-mode-latexsubs.el
@@ -259,7 +259,7 @@
     (puthash "\\^c" "ᶜ" table)
     (puthash "\\^f" "ᶠ" table)
     (puthash "\\^iota" "ᶥ" table)
-    (puthash "\\^Phi" "ᶲ" table)
+    (puthash "\\^ltphi" "ᶲ" table)
     (puthash "\\^z" "ᶻ" table)
     (puthash "\\^theta" "ᶿ" table)
     (puthash "\\enspace" " " table)
@@ -273,8 +273,8 @@
     (puthash "\\lq" "‘" table)
     (puthash "\\rq" "’" table)
     (puthash "\\reapos" "‛" table)
-    (puthash "\\quotedblleft" "“" table)
-    (puthash "\\quotedblright" "”" table)
+    (puthash "\\ldq" "“" table)
+    (puthash "\\rdq" "”" table)
     (puthash "\\dagger" "†" table)
     (puthash "\\ddagger" "‡" table)
     (puthash "\\bullet" "•" table)
@@ -367,8 +367,10 @@
     (puthash "\\frakH" "ℌ" table)
     (puthash "\\bbH" "ℍ" table)
     (puthash "\\planck" "ℎ" table)
+    (puthash "\\ith" "ℎ" table)
     (puthash "\\hslash" "ℏ" table)
     (puthash "\\scrI" "ℐ" table)
+    (puthash "\\frakI" "ℑ" table)
     (puthash "\\Im" "ℑ" table)
     (puthash "\\scrL" "ℒ" table)
     (puthash "\\ell" "ℓ" table)
@@ -379,6 +381,7 @@
     (puthash "\\bbQ" "ℚ" table)
     (puthash "\\scrR" "ℛ" table)
     (puthash "\\Re" "ℜ" table)
+    (puthash "\\frakR" "ℜ" table)
     (puthash "\\bbR" "ℝ" table)
     (puthash "\\xrat" "℞" table)
     (puthash "\\trademark" "™" table)
@@ -652,7 +655,9 @@
     (puthash "\\nequiv" "≢" table)
     (puthash "\\Equiv" "≣" table)
     (puthash "\\le" "≤" table)
+    (puthash "\\leq" "≤" table)
     (puthash "\\ge" "≥" table)
+    (puthash "\\geq" "≥" table)
     (puthash "\\leqq" "≦" table)
     (puthash "\\geqq" "≧" table)
     (puthash "\\lneqq" "≨" table)
@@ -749,6 +754,8 @@
     (puthash "\\veebar" "⊻" table)
     (puthash "\\xor" "⊻" table)
     (puthash "\\barwedge" "⊼" table)
+    (puthash "\\nand" "⊼" table)
+    (puthash "\\nor" "⊽" table)
     (puthash "\\barvee" "⊽" table)
     (puthash "\\rightanglearc" "⊾" table)
     (puthash "\\varlrtriangle" "⊿" table)
@@ -999,6 +1006,7 @@
     (puthash "\\astrosun" "☉" table)
     (puthash "\\:phone:" "☎" table)
     (puthash "\\:ballot_box_with_check:" "☑" table)
+    (puthash "\\:umbrella_with_rain_drops:" "☔" table)
     (puthash "\\:umbrella:" "☔" table)
     (puthash "\\:coffee:" "☕" table)
     (puthash "\\:point_up:" "☝" table)
@@ -1087,6 +1095,7 @@
     (puthash "\\:soccer:" "⚽" table)
     (puthash "\\:baseball:" "⚾" table)
     (puthash "\\:snowman:" "⛄" table)
+    (puthash "\\:snowman_without_snow:" "⛄" table)
     (puthash "\\:partly_sunny:" "⛅" table)
     (puthash "\\:ophiuchus:" "⛎" table)
     (puthash "\\:no_entry:" "⛔" table)
@@ -1343,7 +1352,7 @@
     (puthash "\\upint" "⨛" table)
     (puthash "\\lowint" "⨜" table)
     (puthash "\\join" "⨝" table)
-    (puthash "\\Join" "⨝" table)
+    (puthash "\\bbsemi" "⨟" table)
     (puthash "\\ringplus" "⨢" table)
     (puthash "\\plushat" "⨣" table)
     (puthash "\\simplus" "⨤" table)
@@ -1531,6 +1540,11 @@
     (puthash "\\forksnot" "⫝" table)
     (puthash "\\dashV" "⫣" table)
     (puthash "\\Dashv" "⫤" table)
+    (puthash "\\downvDash" "⫪" table)
+    (puthash "\\Top" "⫪" table)
+    (puthash "\\upvDash" "⫫" table)
+    (puthash "\\Bot" "⫫" table)
+    (puthash "\\indep" "⫫" table)
     (puthash "\\interleave" "⫴" table)
     (puthash "\\tdcol" "⫶" table)
     (puthash "\\lllnest" "⫷" table)
@@ -1615,6 +1629,9 @@
     (puthash "\\:part_alternation_mark:" "〽" table)
     (puthash "\\:congratulations:" "㊗" table)
     (puthash "\\:secret:" "㊙" table)
+    (puthash "\\^uparrow" "ꜛ" table)
+    (puthash "\\^downarrow" "ꜜ" table)
+    (puthash "\\^!" "ꜝ" table)
     (puthash "\\bfA" "𝐀" table)
     (puthash "\\bfB" "𝐁" table)
     (puthash "\\bfC" "𝐂" table)
@@ -2299,7 +2316,7 @@
     (puthash "\\bfbeta" "𝛃" table)
     (puthash "\\bfgamma" "𝛄" table)
     (puthash "\\bfdelta" "𝛅" table)
-    (puthash "\\bfepsilon" "𝛆" table)
+    (puthash "\\bfvarepsilon" "𝛆" table)
     (puthash "\\bfzeta" "𝛇" table)
     (puthash "\\bfeta" "𝛈" table)
     (puthash "\\bftheta" "𝛉" table)
@@ -2321,7 +2338,7 @@
     (puthash "\\bfpsi" "𝛙" table)
     (puthash "\\bfomega" "𝛚" table)
     (puthash "\\bfpartial" "𝛛" table)
-    (puthash "\\bfvarepsilon" "𝛜" table)
+    (puthash "\\bfepsilon" "𝛜" table)
     (puthash "\\bfvartheta" "𝛝" table)
     (puthash "\\bfvarkappa" "𝛞" table)
     (puthash "\\bfphi" "𝛟" table)
@@ -2357,7 +2374,7 @@
     (puthash "\\itbeta" "𝛽" table)
     (puthash "\\itgamma" "𝛾" table)
     (puthash "\\itdelta" "𝛿" table)
-    (puthash "\\itepsilon" "𝜀" table)
+    (puthash "\\itvarepsilon" "𝜀" table)
     (puthash "\\itzeta" "𝜁" table)
     (puthash "\\iteta" "𝜂" table)
     (puthash "\\ittheta" "𝜃" table)
@@ -2374,15 +2391,15 @@
     (puthash "\\itsigma" "𝜎" table)
     (puthash "\\ittau" "𝜏" table)
     (puthash "\\itupsilon" "𝜐" table)
-    (puthash "\\itphi" "𝜑" table)
+    (puthash "\\itvarphi" "𝜑" table)
     (puthash "\\itchi" "𝜒" table)
     (puthash "\\itpsi" "𝜓" table)
     (puthash "\\itomega" "𝜔" table)
     (puthash "\\itpartial" "𝜕" table)
-    (puthash "\\itvarepsilon" "𝜖" table)
+    (puthash "\\itepsilon" "𝜖" table)
     (puthash "\\itvartheta" "𝜗" table)
     (puthash "\\itvarkappa" "𝜘" table)
-    (puthash "\\itvarphi" "𝜙" table)
+    (puthash "\\itphi" "𝜙" table)
     (puthash "\\itvarrho" "𝜚" table)
     (puthash "\\itvarpi" "𝜛" table)
     (puthash "\\biAlpha" "𝜜" table)
@@ -2415,7 +2432,7 @@
     (puthash "\\bibeta" "𝜷" table)
     (puthash "\\bigamma" "𝜸" table)
     (puthash "\\bidelta" "𝜹" table)
-    (puthash "\\biepsilon" "𝜺" table)
+    (puthash "\\bivarepsilon" "𝜺" table)
     (puthash "\\bizeta" "𝜻" table)
     (puthash "\\bieta" "𝜼" table)
     (puthash "\\bitheta" "𝜽" table)
@@ -2432,15 +2449,15 @@
     (puthash "\\bisigma" "𝝈" table)
     (puthash "\\bitau" "𝝉" table)
     (puthash "\\biupsilon" "𝝊" table)
-    (puthash "\\biphi" "𝝋" table)
+    (puthash "\\bivarphi" "𝝋" table)
     (puthash "\\bichi" "𝝌" table)
     (puthash "\\bipsi" "𝝍" table)
     (puthash "\\biomega" "𝝎" table)
     (puthash "\\bipartial" "𝝏" table)
-    (puthash "\\bivarepsilon" "𝝐" table)
+    (puthash "\\biepsilon" "𝝐" table)
     (puthash "\\bivartheta" "𝝑" table)
     (puthash "\\bivarkappa" "𝝒" table)
-    (puthash "\\bivarphi" "𝝓" table)
+    (puthash "\\biphi" "𝝓" table)
     (puthash "\\bivarrho" "𝝔" table)
     (puthash "\\bivarpi" "𝝕" table)
     (puthash "\\bsansAlpha" "𝝖" table)
@@ -2473,7 +2490,7 @@
     (puthash "\\bsansbeta" "𝝱" table)
     (puthash "\\bsansgamma" "𝝲" table)
     (puthash "\\bsansdelta" "𝝳" table)
-    (puthash "\\bsansepsilon" "𝝴" table)
+    (puthash "\\bsansvarepsilon" "𝝴" table)
     (puthash "\\bsanszeta" "𝝵" table)
     (puthash "\\bsanseta" "𝝶" table)
     (puthash "\\bsanstheta" "𝝷" table)
@@ -2490,15 +2507,15 @@
     (puthash "\\bsanssigma" "𝞂" table)
     (puthash "\\bsanstau" "𝞃" table)
     (puthash "\\bsansupsilon" "𝞄" table)
-    (puthash "\\bsansphi" "𝞅" table)
+    (puthash "\\bsansvarphi" "𝞅" table)
     (puthash "\\bsanschi" "𝞆" table)
     (puthash "\\bsanspsi" "𝞇" table)
     (puthash "\\bsansomega" "𝞈" table)
     (puthash "\\bsanspartial" "𝞉" table)
-    (puthash "\\bsansvarepsilon" "𝞊" table)
+    (puthash "\\bsansepsilon" "𝞊" table)
     (puthash "\\bsansvartheta" "𝞋" table)
     (puthash "\\bsansvarkappa" "𝞌" table)
-    (puthash "\\bsansvarphi" "𝞍" table)
+    (puthash "\\bsansphi" "𝞍" table)
     (puthash "\\bsansvarrho" "𝞎" table)
     (puthash "\\bsansvarpi" "𝞏" table)
     (puthash "\\bisansAlpha" "𝞐" table)
@@ -2531,7 +2548,7 @@
     (puthash "\\bisansbeta" "𝞫" table)
     (puthash "\\bisansgamma" "𝞬" table)
     (puthash "\\bisansdelta" "𝞭" table)
-    (puthash "\\bisansepsilon" "𝞮" table)
+    (puthash "\\bisansvarepsilon" "𝞮" table)
     (puthash "\\bisanszeta" "𝞯" table)
     (puthash "\\bisanseta" "𝞰" table)
     (puthash "\\bisanstheta" "𝞱" table)
@@ -2548,15 +2565,15 @@
     (puthash "\\bisanssigma" "𝞼" table)
     (puthash "\\bisanstau" "𝞽" table)
     (puthash "\\bisansupsilon" "𝞾" table)
-    (puthash "\\bisansphi" "𝞿" table)
+    (puthash "\\bisansvarphi" "𝞿" table)
     (puthash "\\bisanschi" "𝟀" table)
     (puthash "\\bisanspsi" "𝟁" table)
     (puthash "\\bisansomega" "𝟂" table)
     (puthash "\\bisanspartial" "𝟃" table)
-    (puthash "\\bisansvarepsilon" "𝟄" table)
+    (puthash "\\bisansepsilon" "𝟄" table)
     (puthash "\\bisansvartheta" "𝟅" table)
     (puthash "\\bisansvarkappa" "𝟆" table)
-    (puthash "\\bisansvarphi" "𝟇" table)
+    (puthash "\\bisansphi" "𝟇" table)
     (puthash "\\bisansvarrho" "𝟈" table)
     (puthash "\\bisansvarpi" "𝟉" table)
     (puthash "\\bfDigamma" "𝟊" table)
@@ -2676,6 +2693,9 @@
     (puthash "\\:sun_with_face:" "🌞" table)
     (puthash "\\:star2:" "🌟" table)
     (puthash "\\:stars:" "🌠" table)
+    (puthash "\\:hotdog:" "🌭" table)
+    (puthash "\\:taco:" "🌮" table)
+    (puthash "\\:burrito:" "🌯" table)
     (puthash "\\:chestnut:" "🌰" table)
     (puthash "\\:seedling:" "🌱" table)
     (puthash "\\:evergreen_tree:" "🌲" table)
@@ -2742,7 +2762,7 @@
     (puthash "\\:cake:" "🍰" table)
     (puthash "\\:bento:" "🍱" table)
     (puthash "\\:stew:" "🍲" table)
-    (puthash "\\:egg:" "🍳" table)
+    (puthash "\\:fried_egg:" "🍳" table)
     (puthash "\\:fork_and_knife:" "🍴" table)
     (puthash "\\:tea:" "🍵" table)
     (puthash "\\:sake:" "🍶" table)
@@ -2752,6 +2772,8 @@
     (puthash "\\:beer:" "🍺" table)
     (puthash "\\:beers:" "🍻" table)
     (puthash "\\:baby_bottle:" "🍼" table)
+    (puthash "\\:champagne:" "🍾" table)
+    (puthash "\\:popcorn:" "🍿" table)
     (puthash "\\:ribbon:" "🎀" table)
     (puthash "\\:gift:" "🎁" table)
     (puthash "\\:birthday:" "🎂" table)
@@ -2809,11 +2831,17 @@
     (puthash "\\:snowboarder:" "🏂" table)
     (puthash "\\:runner:" "🏃" table)
     (puthash "\\:surfer:" "🏄" table)
+    (puthash "\\:sports_medal:" "🏅" table)
     (puthash "\\:trophy:" "🏆" table)
     (puthash "\\:horse_racing:" "🏇" table)
     (puthash "\\:football:" "🏈" table)
     (puthash "\\:rugby_football:" "🏉" table)
     (puthash "\\:swimmer:" "🏊" table)
+    (puthash "\\:cricket_bat_and_ball:" "🏏" table)
+    (puthash "\\:volleyball:" "🏐" table)
+    (puthash "\\:field_hockey_stick_and_ball:" "🏑" table)
+    (puthash "\\:ice_hockey_stick_and_puck:" "🏒" table)
+    (puthash "\\:table_tennis_paddle_and_ball:" "🏓" table)
     (puthash "\\:house:" "🏠" table)
     (puthash "\\:house_with_garden:" "🏡" table)
     (puthash "\\:office:" "🏢" table)
@@ -2831,6 +2859,10 @@
     (puthash "\\:izakaya_lantern:" "🏮" table)
     (puthash "\\:japanese_castle:" "🏯" table)
     (puthash "\\:european_castle:" "🏰" table)
+    (puthash "\\:waving_black_flag:" "🏴" table)
+    (puthash "\\:badminton_racquet_and_shuttlecock:" "🏸" table)
+    (puthash "\\:bow_and_arrow:" "🏹" table)
+    (puthash "\\:amphora:" "🏺" table)
     (puthash "\\:skin-tone-2:" "🏻" table)
     (puthash "\\:skin-tone-3:" "🏼" table)
     (puthash "\\:skin-tone-4:" "🏽" table)
@@ -2866,7 +2898,7 @@
     (puthash "\\:bug:" "🐛" table)
     (puthash "\\:ant:" "🐜" table)
     (puthash "\\:bee:" "🐝" table)
-    (puthash "\\:beetle:" "🐞" table)
+    (puthash "\\:ladybug:" "🐞" table)
     (puthash "\\:fish:" "🐟" table)
     (puthash "\\:tropical_fish:" "🐠" table)
     (puthash "\\:blowfish:" "🐡" table)
@@ -2942,6 +2974,7 @@
     (puthash "\\:woman:" "👩" table)
     (puthash "\\:family:" "👪" table)
     (puthash "\\:couple:" "👫" table)
+    (puthash "\\:man_and_woman_holding_hands:" "👫" table)
     (puthash "\\:two_men_holding_hands:" "👬" table)
     (puthash "\\:two_women_holding_hands:" "👭" table)
     (puthash "\\:cop:" "👮" table)
@@ -3060,6 +3093,7 @@
     (puthash "\\:pager:" "📟" table)
     (puthash "\\:fax:" "📠" table)
     (puthash "\\:satellite:" "📡" table)
+    (puthash "\\:satellite_antenna:" "📡" table)
     (puthash "\\:loudspeaker:" "📢" table)
     (puthash "\\:mega:" "📣" table)
     (puthash "\\:outbox_tray:" "📤" table)
@@ -3082,10 +3116,12 @@
     (puthash "\\:no_mobile_phones:" "📵" table)
     (puthash "\\:signal_strength:" "📶" table)
     (puthash "\\:camera:" "📷" table)
+    (puthash "\\:camera_with_flash:" "📸" table)
     (puthash "\\:video_camera:" "📹" table)
     (puthash "\\:tv:" "📺" table)
     (puthash "\\:radio:" "📻" table)
     (puthash "\\:vhs:" "📼" table)
+    (puthash "\\:prayer_beads:" "📿" table)
     (puthash "\\:twisted_rightwards_arrows:" "🔀" table)
     (puthash "\\:repeat:" "🔁" table)
     (puthash "\\:repeat_one:" "🔂" table)
@@ -3148,6 +3184,10 @@
     (puthash "\\:small_red_triangle_down:" "🔻" table)
     (puthash "\\:arrow_up_small:" "🔼" table)
     (puthash "\\:arrow_down_small:" "🔽" table)
+    (puthash "\\:kaaba:" "🕋" table)
+    (puthash "\\:mosque:" "🕌" table)
+    (puthash "\\:synagogue:" "🕍" table)
+    (puthash "\\:menorah_with_nine_branches:" "🕎" table)
     (puthash "\\:clock1:" "🕐" table)
     (puthash "\\:clock2:" "🕑" table)
     (puthash "\\:clock3:" "🕒" table)
@@ -3172,6 +3212,10 @@
     (puthash "\\:clock1030:" "🕥" table)
     (puthash "\\:clock1130:" "🕦" table)
     (puthash "\\:clock1230:" "🕧" table)
+    (puthash "\\:man_dancing:" "🕺" table)
+    (puthash "\\:middle_finger:" "🖕" table)
+    (puthash "\\:spock-hand:" "🖖" table)
+    (puthash "\\:black_heart:" "🖤" table)
     (puthash "\\:mount_fuji:" "🗻" table)
     (puthash "\\:tokyo_tower:" "🗼" table)
     (puthash "\\:statue_of_liberty:" "🗽" table)
@@ -3242,6 +3286,10 @@
     (puthash "\\:pouting_cat:" "😾" table)
     (puthash "\\:crying_cat_face:" "😿" table)
     (puthash "\\:scream_cat:" "🙀" table)
+    (puthash "\\:slightly_frowning_face:" "🙁" table)
+    (puthash "\\:slightly_smiling_face:" "🙂" table)
+    (puthash "\\:upside_down_face:" "🙃" table)
+    (puthash "\\:face_with_rolling_eyes:" "🙄" table)
     (puthash "\\:no_good:" "🙅" table)
     (puthash "\\:ok_woman:" "🙆" table)
     (puthash "\\:bow:" "🙇" table)
@@ -3323,5 +3371,328 @@
     (puthash "\\:customs:" "🛃" table)
     (puthash "\\:baggage_claim:" "🛄" table)
     (puthash "\\:left_luggage:" "🛅" table)
+    (puthash "\\:sleeping_accommodation:" "🛌" table)
+    (puthash "\\:place_of_worship:" "🛐" table)
+    (puthash "\\:octagonal_sign:" "🛑" table)
+    (puthash "\\:shopping_trolley:" "🛒" table)
+    (puthash "\\:hindu_temple:" "🛕" table)
+    (puthash "\\:hut:" "🛖" table)
+    (puthash "\\:elevator:" "🛗" table)
+    (puthash "\\:airplane_departure:" "🛫" table)
+    (puthash "\\:airplane_arriving:" "🛬" table)
+    (puthash "\\:scooter:" "🛴" table)
+    (puthash "\\:motor_scooter:" "🛵" table)
+    (puthash "\\:canoe:" "🛶" table)
+    (puthash "\\:sled:" "🛷" table)
+    (puthash "\\:flying_saucer:" "🛸" table)
+    (puthash "\\:skateboard:" "🛹" table)
+    (puthash "\\:auto_rickshaw:" "🛺" table)
+    (puthash "\\:pickup_truck:" "🛻" table)
+    (puthash "\\:roller_skate:" "🛼" table)
+    (puthash "\\:large_orange_circle:" "🟠" table)
+    (puthash "\\:large_yellow_circle:" "🟡" table)
+    (puthash "\\:large_green_circle:" "🟢" table)
+    (puthash "\\:large_purple_circle:" "🟣" table)
+    (puthash "\\:large_brown_circle:" "🟤" table)
+    (puthash "\\:large_red_square:" "🟥" table)
+    (puthash "\\:large_blue_square:" "🟦" table)
+    (puthash "\\:large_orange_square:" "🟧" table)
+    (puthash "\\:large_yellow_square:" "🟨" table)
+    (puthash "\\:large_green_square:" "🟩" table)
+    (puthash "\\:large_purple_square:" "🟪" table)
+    (puthash "\\:large_brown_square:" "🟫" table)
+    (puthash "\\:pinched_fingers:" "🤌" table)
+    (puthash "\\:white_heart:" "🤍" table)
+    (puthash "\\:brown_heart:" "🤎" table)
+    (puthash "\\:pinching_hand:" "🤏" table)
+    (puthash "\\:zipper_mouth_face:" "🤐" table)
+    (puthash "\\:money_mouth_face:" "🤑" table)
+    (puthash "\\:face_with_thermometer:" "🤒" table)
+    (puthash "\\:nerd_face:" "🤓" table)
+    (puthash "\\:thinking_face:" "🤔" table)
+    (puthash "\\:face_with_head_bandage:" "🤕" table)
+    (puthash "\\:robot_face:" "🤖" table)
+    (puthash "\\:hugging_face:" "🤗" table)
+    (puthash "\\:the_horns:" "🤘" table)
+    (puthash "\\:call_me_hand:" "🤙" table)
+    (puthash "\\:raised_back_of_hand:" "🤚" table)
+    (puthash "\\:left-facing_fist:" "🤛" table)
+    (puthash "\\:right-facing_fist:" "🤜" table)
+    (puthash "\\:handshake:" "🤝" table)
+    (puthash "\\:crossed_fingers:" "🤞" table)
+    (puthash "\\:i_love_you_hand_sign:" "🤟" table)
+    (puthash "\\:face_with_cowboy_hat:" "🤠" table)
+    (puthash "\\:clown_face:" "🤡" table)
+    (puthash "\\:nauseated_face:" "🤢" table)
+    (puthash "\\:rolling_on_the_floor_laughing:" "🤣" table)
+    (puthash "\\:drooling_face:" "🤤" table)
+    (puthash "\\:lying_face:" "🤥" table)
+    (puthash "\\:face_palm:" "🤦" table)
+    (puthash "\\:sneezing_face:" "🤧" table)
+    (puthash "\\:face_with_raised_eyebrow:" "🤨" table)
+    (puthash "\\:star-struck:" "🤩" table)
+    (puthash "\\:zany_face:" "🤪" table)
+    (puthash "\\:shushing_face:" "🤫" table)
+    (puthash "\\:face_with_symbols_on_mouth:" "🤬" table)
+    (puthash "\\:face_with_hand_over_mouth:" "🤭" table)
+    (puthash "\\:face_vomiting:" "🤮" table)
+    (puthash "\\:exploding_head:" "🤯" table)
+    (puthash "\\:pregnant_woman:" "🤰" table)
+    (puthash "\\:breast-feeding:" "🤱" table)
+    (puthash "\\:palms_up_together:" "🤲" table)
+    (puthash "\\:selfie:" "🤳" table)
+    (puthash "\\:prince:" "🤴" table)
+    (puthash "\\:person_in_tuxedo:" "🤵" table)
+    (puthash "\\:mrs_claus:" "🤶" table)
+    (puthash "\\:shrug:" "🤷" table)
+    (puthash "\\:person_doing_cartwheel:" "🤸" table)
+    (puthash "\\:juggling:" "🤹" table)
+    (puthash "\\:fencer:" "🤺" table)
+    (puthash "\\:wrestlers:" "🤼" table)
+    (puthash "\\:water_polo:" "🤽" table)
+    (puthash "\\:handball:" "🤾" table)
+    (puthash "\\:diving_mask:" "🤿" table)
+    (puthash "\\:wilted_flower:" "🥀" table)
+    (puthash "\\:drum_with_drumsticks:" "🥁" table)
+    (puthash "\\:clinking_glasses:" "🥂" table)
+    (puthash "\\:tumbler_glass:" "🥃" table)
+    (puthash "\\:spoon:" "🥄" table)
+    (puthash "\\:goal_net:" "🥅" table)
+    (puthash "\\:first_place_medal:" "🥇" table)
+    (puthash "\\:second_place_medal:" "🥈" table)
+    (puthash "\\:third_place_medal:" "🥉" table)
+    (puthash "\\:boxing_glove:" "🥊" table)
+    (puthash "\\:martial_arts_uniform:" "🥋" table)
+    (puthash "\\:curling_stone:" "🥌" table)
+    (puthash "\\:lacrosse:" "🥍" table)
+    (puthash "\\:softball:" "🥎" table)
+    (puthash "\\:flying_disc:" "🥏" table)
+    (puthash "\\:croissant:" "🥐" table)
+    (puthash "\\:avocado:" "🥑" table)
+    (puthash "\\:cucumber:" "🥒" table)
+    (puthash "\\:bacon:" "🥓" table)
+    (puthash "\\:potato:" "🥔" table)
+    (puthash "\\:carrot:" "🥕" table)
+    (puthash "\\:baguette_bread:" "🥖" table)
+    (puthash "\\:green_salad:" "🥗" table)
+    (puthash "\\:shallow_pan_of_food:" "🥘" table)
+    (puthash "\\:stuffed_flatbread:" "🥙" table)
+    (puthash "\\:egg:" "🥚" table)
+    (puthash "\\:glass_of_milk:" "🥛" table)
+    (puthash "\\:peanuts:" "🥜" table)
+    (puthash "\\:kiwifruit:" "🥝" table)
+    (puthash "\\:pancakes:" "🥞" table)
+    (puthash "\\:dumpling:" "🥟" table)
+    (puthash "\\:fortune_cookie:" "🥠" table)
+    (puthash "\\:takeout_box:" "🥡" table)
+    (puthash "\\:chopsticks:" "🥢" table)
+    (puthash "\\:bowl_with_spoon:" "🥣" table)
+    (puthash "\\:cup_with_straw:" "🥤" table)
+    (puthash "\\:coconut:" "🥥" table)
+    (puthash "\\:broccoli:" "🥦" table)
+    (puthash "\\:pie:" "🥧" table)
+    (puthash "\\:pretzel:" "🥨" table)
+    (puthash "\\:cut_of_meat:" "🥩" table)
+    (puthash "\\:sandwich:" "🥪" table)
+    (puthash "\\:canned_food:" "🥫" table)
+    (puthash "\\:leafy_green:" "🥬" table)
+    (puthash "\\:mango:" "🥭" table)
+    (puthash "\\:moon_cake:" "🥮" table)
+    (puthash "\\:bagel:" "🥯" table)
+    (puthash "\\:smiling_face_with_3_hearts:" "🥰" table)
+    (puthash "\\:yawning_face:" "🥱" table)
+    (puthash "\\:smiling_face_with_tear:" "🥲" table)
+    (puthash "\\:partying_face:" "🥳" table)
+    (puthash "\\:woozy_face:" "🥴" table)
+    (puthash "\\:hot_face:" "🥵" table)
+    (puthash "\\:cold_face:" "🥶" table)
+    (puthash "\\:ninja:" "🥷" table)
+    (puthash "\\:disguised_face:" "🥸" table)
+    (puthash "\\:pleading_face:" "🥺" table)
+    (puthash "\\:sari:" "🥻" table)
+    (puthash "\\:lab_coat:" "🥼" table)
+    (puthash "\\:goggles:" "🥽" table)
+    (puthash "\\:hiking_boot:" "🥾" table)
+    (puthash "\\:womans_flat_shoe:" "🥿" table)
+    (puthash "\\:crab:" "🦀" table)
+    (puthash "\\:lion_face:" "🦁" table)
+    (puthash "\\:scorpion:" "🦂" table)
+    (puthash "\\:turkey:" "🦃" table)
+    (puthash "\\:unicorn_face:" "🦄" table)
+    (puthash "\\:eagle:" "🦅" table)
+    (puthash "\\:duck:" "🦆" table)
+    (puthash "\\:bat:" "🦇" table)
+    (puthash "\\:shark:" "🦈" table)
+    (puthash "\\:owl:" "🦉" table)
+    (puthash "\\:fox_face:" "🦊" table)
+    (puthash "\\:butterfly:" "🦋" table)
+    (puthash "\\:deer:" "🦌" table)
+    (puthash "\\:gorilla:" "🦍" table)
+    (puthash "\\:lizard:" "🦎" table)
+    (puthash "\\:rhinoceros:" "🦏" table)
+    (puthash "\\:shrimp:" "🦐" table)
+    (puthash "\\:squid:" "🦑" table)
+    (puthash "\\:giraffe_face:" "🦒" table)
+    (puthash "\\:zebra_face:" "🦓" table)
+    (puthash "\\:hedgehog:" "🦔" table)
+    (puthash "\\:sauropod:" "🦕" table)
+    (puthash "\\:t-rex:" "🦖" table)
+    (puthash "\\:cricket:" "🦗" table)
+    (puthash "\\:kangaroo:" "🦘" table)
+    (puthash "\\:llama:" "🦙" table)
+    (puthash "\\:peacock:" "🦚" table)
+    (puthash "\\:hippopotamus:" "🦛" table)
+    (puthash "\\:parrot:" "🦜" table)
+    (puthash "\\:raccoon:" "🦝" table)
+    (puthash "\\:lobster:" "🦞" table)
+    (puthash "\\:mosquito:" "🦟" table)
+    (puthash "\\:microbe:" "🦠" table)
+    (puthash "\\:badger:" "🦡" table)
+    (puthash "\\:swan:" "🦢" table)
+    (puthash "\\:mammoth:" "🦣" table)
+    (puthash "\\:dodo:" "🦤" table)
+    (puthash "\\:sloth:" "🦥" table)
+    (puthash "\\:otter:" "🦦" table)
+    (puthash "\\:orangutan:" "🦧" table)
+    (puthash "\\:skunk:" "🦨" table)
+    (puthash "\\:flamingo:" "🦩" table)
+    (puthash "\\:oyster:" "🦪" table)
+    (puthash "\\:beaver:" "🦫" table)
+    (puthash "\\:bison:" "🦬" table)
+    (puthash "\\:seal:" "🦭" table)
+    (puthash "\\:guide_dog:" "🦮" table)
+    (puthash "\\:probing_cane:" "🦯" table)
+    (puthash "\\:bone:" "🦴" table)
+    (puthash "\\:leg:" "🦵" table)
+    (puthash "\\:foot:" "🦶" table)
+    (puthash "\\:tooth:" "🦷" table)
+    (puthash "\\:superhero:" "🦸" table)
+    (puthash "\\:supervillain:" "🦹" table)
+    (puthash "\\:safety_vest:" "🦺" table)
+    (puthash "\\:ear_with_hearing_aid:" "🦻" table)
+    (puthash "\\:motorized_wheelchair:" "🦼" table)
+    (puthash "\\:manual_wheelchair:" "🦽" table)
+    (puthash "\\:mechanical_arm:" "🦾" table)
+    (puthash "\\:mechanical_leg:" "🦿" table)
+    (puthash "\\:cheese_wedge:" "🧀" table)
+    (puthash "\\:cupcake:" "🧁" table)
+    (puthash "\\:salt:" "🧂" table)
+    (puthash "\\:beverage_box:" "🧃" table)
+    (puthash "\\:garlic:" "🧄" table)
+    (puthash "\\:onion:" "🧅" table)
+    (puthash "\\:falafel:" "🧆" table)
+    (puthash "\\:waffle:" "🧇" table)
+    (puthash "\\:butter:" "🧈" table)
+    (puthash "\\:mate_drink:" "🧉" table)
+    (puthash "\\:ice_cube:" "🧊" table)
+    (puthash "\\:bubble_tea:" "🧋" table)
+    (puthash "\\:standing_person:" "🧍" table)
+    (puthash "\\:kneeling_person:" "🧎" table)
+    (puthash "\\:deaf_person:" "🧏" table)
+    (puthash "\\:face_with_monocle:" "🧐" table)
+    (puthash "\\:adult:" "🧑" table)
+    (puthash "\\:child:" "🧒" table)
+    (puthash "\\:older_adult:" "🧓" table)
+    (puthash "\\:bearded_person:" "🧔" table)
+    (puthash "\\:person_with_headscarf:" "🧕" table)
+    (puthash "\\:person_in_steamy_room:" "🧖" table)
+    (puthash "\\:person_climbing:" "🧗" table)
+    (puthash "\\:person_in_lotus_position:" "🧘" table)
+    (puthash "\\:mage:" "🧙" table)
+    (puthash "\\:fairy:" "🧚" table)
+    (puthash "\\:vampire:" "🧛" table)
+    (puthash "\\:merperson:" "🧜" table)
+    (puthash "\\:elf:" "🧝" table)
+    (puthash "\\:genie:" "🧞" table)
+    (puthash "\\:zombie:" "🧟" table)
+    (puthash "\\:brain:" "🧠" table)
+    (puthash "\\:orange_heart:" "🧡" table)
+    (puthash "\\:billed_cap:" "🧢" table)
+    (puthash "\\:scarf:" "🧣" table)
+    (puthash "\\:gloves:" "🧤" table)
+    (puthash "\\:coat:" "🧥" table)
+    (puthash "\\:socks:" "🧦" table)
+    (puthash "\\:red_envelope:" "🧧" table)
+    (puthash "\\:firecracker:" "🧨" table)
+    (puthash "\\:jigsaw:" "🧩" table)
+    (puthash "\\:test_tube:" "🧪" table)
+    (puthash "\\:petri_dish:" "🧫" table)
+    (puthash "\\:dna:" "🧬" table)
+    (puthash "\\:compass:" "🧭" table)
+    (puthash "\\:abacus:" "🧮" table)
+    (puthash "\\:fire_extinguisher:" "🧯" table)
+    (puthash "\\:toolbox:" "🧰" table)
+    (puthash "\\:bricks:" "🧱" table)
+    (puthash "\\:magnet:" "🧲" table)
+    (puthash "\\:luggage:" "🧳" table)
+    (puthash "\\:lotion_bottle:" "🧴" table)
+    (puthash "\\:thread:" "🧵" table)
+    (puthash "\\:yarn:" "🧶" table)
+    (puthash "\\:safety_pin:" "🧷" table)
+    (puthash "\\:teddy_bear:" "🧸" table)
+    (puthash "\\:broom:" "🧹" table)
+    (puthash "\\:basket:" "🧺" table)
+    (puthash "\\:roll_of_paper:" "🧻" table)
+    (puthash "\\:soap:" "🧼" table)
+    (puthash "\\:sponge:" "🧽" table)
+    (puthash "\\:receipt:" "🧾" table)
+    (puthash "\\:nazar_amulet:" "🧿" table)
+    (puthash "\\:ballet_shoes:" "🩰" table)
+    (puthash "\\:one-piece_swimsuit:" "🩱" table)
+    (puthash "\\:briefs:" "🩲" table)
+    (puthash "\\:shorts:" "🩳" table)
+    (puthash "\\:thong_sandal:" "🩴" table)
+    (puthash "\\:drop_of_blood:" "🩸" table)
+    (puthash "\\:adhesive_bandage:" "🩹" table)
+    (puthash "\\:stethoscope:" "🩺" table)
+    (puthash "\\:yo-yo:" "🪀" table)
+    (puthash "\\:kite:" "🪁" table)
+    (puthash "\\:parachute:" "🪂" table)
+    (puthash "\\:boomerang:" "🪃" table)
+    (puthash "\\:magic_wand:" "🪄" table)
+    (puthash "\\:pinata:" "🪅" table)
+    (puthash "\\:nesting_dolls:" "🪆" table)
+    (puthash "\\:ringed_planet:" "🪐" table)
+    (puthash "\\:chair:" "🪑" table)
+    (puthash "\\:razor:" "🪒" table)
+    (puthash "\\:axe:" "🪓" table)
+    (puthash "\\:diya_lamp:" "🪔" table)
+    (puthash "\\:banjo:" "🪕" table)
+    (puthash "\\:military_helmet:" "🪖" table)
+    (puthash "\\:accordion:" "🪗" table)
+    (puthash "\\:long_drum:" "🪘" table)
+    (puthash "\\:coin:" "🪙" table)
+    (puthash "\\:carpentry_saw:" "🪚" table)
+    (puthash "\\:screwdriver:" "🪛" table)
+    (puthash "\\:ladder:" "🪜" table)
+    (puthash "\\:hook:" "🪝" table)
+    (puthash "\\:mirror:" "🪞" table)
+    (puthash "\\:window:" "🪟" table)
+    (puthash "\\:plunger:" "🪠" table)
+    (puthash "\\:sewing_needle:" "🪡" table)
+    (puthash "\\:knot:" "🪢" table)
+    (puthash "\\:bucket:" "🪣" table)
+    (puthash "\\:mouse_trap:" "🪤" table)
+    (puthash "\\:toothbrush:" "🪥" table)
+    (puthash "\\:headstone:" "🪦" table)
+    (puthash "\\:placard:" "🪧" table)
+    (puthash "\\:rock:" "🪨" table)
+    (puthash "\\:fly:" "🪰" table)
+    (puthash "\\:worm:" "🪱" table)
+    (puthash "\\:beetle:" "🪲" table)
+    (puthash "\\:cockroach:" "🪳" table)
+    (puthash "\\:potted_plant:" "🪴" table)
+    (puthash "\\:wood:" "🪵" table)
+    (puthash "\\:feather:" "🪶" table)
+    (puthash "\\:anatomical_heart:" "🫀" table)
+    (puthash "\\:lungs:" "🫁" table)
+    (puthash "\\:people_hugging:" "🫂" table)
+    (puthash "\\:blueberries:" "🫐" table)
+    (puthash "\\:bell_pepper:" "🫑" table)
+    (puthash "\\:olive:" "🫒" table)
+    (puthash "\\:flatbread:" "🫓" table)
+    (puthash "\\:tamale:" "🫔" table)
+    (puthash "\\:fondue:" "🫕" table)
+    (puthash "\\:teapot:" "🫖" table)
     table))
 (provide 'julia-mode-latexsubs)
diff --git a/julia-mode-tests.el b/julia-mode-tests.el
index 06b71cfd19..42c33a3797 100644
--- a/julia-mode-tests.el
+++ b/julia-mode-tests.el
@@ -54,16 +54,20 @@
        (should (equal (buffer-substring-no-properties (point-min) (point-max))
                       ,to)))))
 
-(defmacro julia--should-font-lock (text pos face)
-  "Assert that TEXT at position POS gets font-locked with FACE in 
`julia-mode'."
-  `(with-temp-buffer
+(defun julia--get-font-lock (text pos)
+  "Get the face of `text' at `pos' when font-locked as Julia code in this 
mode."
+  (with-temp-buffer
      (julia-mode)
-     (insert ,text)
+     (insert text)
      (if (fboundp 'font-lock-ensure)
          (font-lock-ensure (point-min) (point-max))
        (with-no-warnings
          (font-lock-fontify-buffer)))
-     (should (eq ,face (get-text-property ,pos 'face)))))
+     (get-text-property pos 'face)))
+
+(defmacro julia--should-font-lock (text pos face)
+  "Assert that TEXT at position POS gets font-locked with FACE in 
`julia-mode'."
+  `(should (eq ,face (julia--get-font-lock ,text ,pos))))
 
 (defmacro julia--should-move-point (text fun from to &optional end arg)
   "With TEXT in `julia-mode', after calling FUN, the point should move FROM\
@@ -88,6 +92,8 @@ matching line or end of match if END is non-nil.  Optional 
ARG is passed to FUN.
                                       (point-at-bol)))
                            ,to)))))
 
+;;; indent tests
+
 (ert-deftest julia--test-indent-if ()
   "We should indent inside if bodies."
   (julia--should-indent
@@ -384,6 +390,15 @@ notpartofit"
    "using Foo: bar ,
     baz,
     quux
+notpartofit")
+  (julia--should-indent
+   "using Foo.Bar: bar ,
+baz,
+quux
+notpartofit"
+   "using Foo.Bar: bar ,
+    baz,
+    quux
 notpartofit"))
 
 (ert-deftest julia--test-indent-anonymous-function ()
@@ -452,6 +467,135 @@ end"
 end")
   )
 
+(ert-deftest julia--test-indent-hanging ()
+  "Test indentation for line following a hanging operator."
+  (julia--should-indent
+   "
+f(x) =
+x*
+x"
+   "
+f(x) =
+    x*
+    x")
+  (julia--should-indent
+   "
+a = \"#\" |>
+identity"
+   "
+a = \"#\" |>
+    identity")
+  ;; make sure we don't interpret a hanging operator in a comment as
+  ;; an actual hanging operator for indentation
+  (julia--should-indent
+   "
+a = \"#\" # |>
+identity"
+   "
+a = \"#\" # |>
+identity"))
+
+(ert-deftest julia--test-indent-quoted-single-quote ()
+  "We should indent after seeing a character constant containing a single 
quote character."
+  (julia--should-indent "
+if c in ('\'')
+s = \"$c$c\"*string[startpos:pos]
+end
+" "
+if c in ('\'')
+    s = \"$c$c\"*string[startpos:pos]
+end
+"))
+
+(ert-deftest julia--test-indent-block-inside-paren ()
+  "We should indent a block inside of a parenthetical."
+  (julia--should-indent "
+variable = func(
+arg1,
+arg2,
+if cond
+statement()
+arg3
+else
+arg3
+end,
+arg4
+)" "
+variable = func(
+    arg1,
+    arg2,
+    if cond
+        statement()
+        arg3
+    else
+        arg3
+    end,
+    arg4
+)"))
+
+(ert-deftest julia--test-indent-block-inside-hanging-paren ()
+  "We should indent a block inside of a hanging parenthetical."
+  (julia--should-indent "
+variable = func(arg1,
+arg2,
+if cond
+statement()
+arg3
+else
+arg3
+end,
+arg4
+)" "
+variable = func(arg1,
+                arg2,
+                if cond
+                    statement()
+                    arg3
+                else
+                    arg3
+                end,
+                arg4
+                )"))
+
+(ert-deftest julia--test-indent-nested-block-inside-paren ()
+  "We should indent a nested block inside of a parenthetical."
+  (julia--should-indent "
+variable = func(
+arg1,
+if cond1
+statement()
+if cond2
+statement()
+end
+arg3
+end,
+arg4
+)" "
+variable = func(
+    arg1,
+    if cond1
+        statement()
+        if cond2
+            statement()
+        end
+        arg3
+    end,
+    arg4
+)"))
+
+(ert-deftest julia--test-indent-block-next-to-paren ()
+  (julia--should-indent "
+var = func(begin
+test
+end
+)" "
+var = func(begin
+               test
+           end
+           )"))
+
+;;; font-lock tests
+
 (ert-deftest julia--test-symbol-font-locking-at-bol ()
   "Symbols get font-locked at beginning or line."
   (julia--should-font-lock
@@ -532,6 +676,79 @@ end")
     (julia--should-font-lock string 74 font-lock-type-face) ; B
     ))
 
+(ert-deftest julia--test-single-quote-string-font-lock ()
+  "Test that single quoted strings are font-locked correctly even with 
escapes."
+  ;; Issue #15
+  (let ((s1 "\"a\\\"b\"c"))
+    (julia--should-font-lock s1 2 font-lock-string-face)
+    (julia--should-font-lock s1 5 font-lock-string-face)
+    (julia--should-font-lock s1 7 nil)))
+
+(ert-deftest julia--test-triple-quote-string-font-lock ()
+  "Test that triple quoted strings are font-locked correctly even with 
escapes."
+  ;; Issue #15
+  (let ((s1 "\"\"\"a\\\"\\\"\"b\"\"\"d")
+        (s2 "\"\"\"a\\\"\"\"b\"\"\"d")
+        (s3 "\"\"\"a```b\"\"\"d")
+        (s4 "\\\"\"\"a\\\"\"\"b\"\"\"d")
+        (s5 "\"\"\"a\\\"\"\"\"b"))
+    (julia--should-font-lock s1 4 font-lock-string-face)
+    (julia--should-font-lock s1 10 font-lock-string-face)
+    (julia--should-font-lock s1 14 nil)
+    (julia--should-font-lock s2 4 font-lock-string-face)
+    (julia--should-font-lock s2 9 font-lock-string-face)
+    (julia--should-font-lock s2 13 nil)
+    (julia--should-font-lock s3 4 font-lock-string-face)
+    (julia--should-font-lock s3 8 font-lock-string-face)
+    (julia--should-font-lock s3 12 nil)
+    (julia--should-font-lock s4 5 font-lock-string-face)
+    (julia--should-font-lock s4 10 font-lock-string-face)
+    (julia--should-font-lock s4 14 nil)
+    (julia--should-font-lock s5 4 font-lock-string-face)
+    (julia--should-font-lock s5 10 nil)))
+
+(ert-deftest julia--test-triple-quote-cmd-font-lock ()
+  "Test that triple-quoted cmds are font-locked correctly even with escapes."
+  (let ((s1 "```a\\`\\``b```d")
+        (s2 "```a\\```b```d")
+        (s3 "```a\"\"\"b```d")
+        (s4 "\\```a\\```b```d"))
+    (julia--should-font-lock s1 4 font-lock-string-face)
+    (julia--should-font-lock s1 10 font-lock-string-face)
+    (julia--should-font-lock s1 14 nil)
+    (julia--should-font-lock s2 4 font-lock-string-face)
+    (julia--should-font-lock s2 9 font-lock-string-face)
+    (julia--should-font-lock s2 13 nil)
+    (julia--should-font-lock s3 4 font-lock-string-face)
+    (julia--should-font-lock s3 8 font-lock-string-face)
+    (julia--should-font-lock s3 12 nil)
+    (julia--should-font-lock s4 5 font-lock-string-face)
+    (julia--should-font-lock s4 10 font-lock-string-face)
+    (julia--should-font-lock s4 14 nil)))
+
+(ert-deftest julia--test-ccall-font-lock ()
+  (let ((s1 "t = ccall(:clock, Int32, ())"))
+    (julia--should-font-lock s1 5 font-lock-builtin-face)
+    (julia--should-font-lock s1 4 nil)
+    (julia--should-font-lock s1 10 nil)))
+
+(ert-deftest julia--test-char-const-font-lock ()
+  (dolist (c '("'\\''"
+               "'\\\"'"
+               "'\\\\'"
+               "'\\010'"
+               "'\\xfe'"
+               "'\\uabcd'"
+               "'\\Uabcdef01'"
+               "'\\n'"
+               "'a'" "'z'" "'''"))
+    (let ((c (format " %s " c)))
+      (progn
+        (julia--should-font-lock c 1 nil)
+        (julia--should-font-lock c 2 font-lock-string-face)
+        (julia--should-font-lock c (- (length c) 1) font-lock-string-face)
+        (julia--should-font-lock c (length c) nil)))))
+
 (ert-deftest julia--test-const-def-font-lock ()
   (let ((string "const foo = \"bar\""))
     (julia--should-font-lock string 1 font-lock-keyword-face) ; const
@@ -551,8 +768,8 @@ end")
   "Point moves to beginning of multi-line assignment function."
   (julia--should-move-point
     "f(x)=
-x*
-x" 'beginning-of-defun "\\*\nx" 1))
+    x*
+    x" 'beginning-of-defun "x$" 1))
 
 (ert-deftest julia--test-beginning-of-defun-assn-3 ()
   "Point moves to beginning of multi-line assignment function adjoining
@@ -706,6 +923,14 @@ hello world
     ;; instead of 1.
     (should (= 1 (nth 8 (syntax-ppss 5))))))
 
+(ert-deftest julia--test-triple-quoted-cmd-syntax ()
+  (with-temp-buffer
+    (julia-mode)
+    (insert "```
+hello world
+```")
+    (should (= 1 (nth 8 (syntax-ppss 5))))))
+
 (ert-deftest julia--test-backslash-syntax ()
   (with-temp-buffer
     (julia-mode)
diff --git a/julia-mode.el b/julia-mode.el
index a134991842..01ca779a6b 100644
--- a/julia-mode.el
+++ b/julia-mode.el
@@ -45,22 +45,20 @@
   "Major mode for the julia programming language."
   :group 'languages
   :prefix "julia-")
+;; all custom variables are automatically added to the most recent defgroup
 
 (defcustom julia-indent-offset 4
   "Number of spaces per indentation level."
-  :type 'integer
-  :group 'julia)
+  :safe (lambda (n) (and (> n 1) (<= n 8)))
+  :type 'integer)
 
 (defface julia-macro-face
   '((t :inherit font-lock-preprocessor-face))
-  "Face for Julia macro invocations."
-  :group 'julia-mode)
+  "Face for Julia macro invocations.")
 
 (defface julia-quoted-symbol-face
   '((t :inherit font-lock-constant-face))
-  "Face for quoted Julia symbols, e.g. :foo."
-  :group 'julia-mode)
-
+  "Face for quoted Julia symbols, e.g. :foo.")
 
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.jl\\'" . julia-mode))
@@ -112,76 +110,82 @@
             (syntax open-parenthesis)
             (syntax whitespace)
             bol)
-        (group "'")
-        (group
-         (or (repeat 0 8 (not (any "'"))) (not (any "\\"))
-             "\\\\"))
-        (group "'"))))
+        (group "'")        ; start single quote of character constant
+        (or                ; two alternatives
+         (not (any "\\"))  ; one character, not backslash
+            (seq "\\"         ; sequence of a backslash followed by ...
+              (or          ; five alternatives
+               (any "\\'\"abfnrtv")          ; single character escape
+               (repeat 1 3 (any "0-7"))      ; octal escape
+               (seq "x" (repeat 1 2 hex))    ; hex escape
+               (seq "u" (repeat 1 4 hex))    ; unicode escape
+               (seq "U" (repeat 1 8 hex))))) ; extended unicode escape
+        (group "'"))))     ; end single quote of character constant
 
 (defconst julia-hanging-operator-regexp
   ;; taken from julia-parser.scm
-  (concat "^[^#\n]+ "
-          (regexp-opt
-           '( ;; conditional
-             "?"
-             ;; assignment
-             "=" ":=" "+=" "-=" "*=" "/=" "//=" ".//=" ".*=" "./=" "\\=" ".\\="
-             "^=" ".^=" "÷=" ".÷=" "%=" ".%=" "|=" "&=" "$=" "=>" "<<=" ">>="
-             ">>>=" "~" ".+=" ".-="
-             ;; arrow
-             "--" "-->" "←" "→" "↔" "↚" "↛" "↠" "↣" "↦" "↮" "⇎" "⇏" "⇒" "⇔" "⇴"
-             "⇶" "⇷" "⇸" "⇹" "⇺" "⇻" "⇼" "⇽" "⇾" "⇿" "⟵" "⟶" "⟷" "⟷" "⟹"
-             "⟺" "⟻" "⟼" "⟽" "⟾" "⟿" "⤀" "⤁" "⤂" "⤃" "⤄" "⤅" "⤆" "⤇" "⤌"
-             "⤍" "⤎" "⤏" "⤐" "⤑" "⤔" "⤕" "⤖" "⤗" "⤘" "⤝" "⤞" "⤟" "⤠" "⥄" "⥅"
-             "⥆" "⥇" "⥈" "⥊" "⥋" "⥎" "⥐" "⥒" "⥓" "⥖" "⥗" "⥚" "⥛" "⥞" "⥟" "⥢"
-             "⥤" "⥦" "⥧" "⥨" "⥩" "⥪" "⥫" "⥬" "⥭" "⥰" "⧴" "⬱" "⬰" "⬲" "⬳" "⬴"
-             "⬵" "⬶" "⬷" "⬸" "⬹" "⬺" "⬻" "⬼" "⬽" "⬾" "⬿" "⭀" "⭁" "⭂" "⭃" "⭄"
-             "⭇" "⭈" "⭉" "⭊" "⭋" "⭌" "←" "→"
-             ;; or and and
-             "&&" "||"
-             ;; comparison
-             ">" "<" ">=" "≥" "<=" "≤" "==" "===" "≡" "!=" "≠" "!==" "≢" ".>"
-             ".<" ".>=" ".≥" ".<=" ".≤" ".==" ".!=" ".≠" ".=" ".!" "<:" ">:" 
"∈"
-             "∉" "∋" "∌" "⊆" "⊈" "⊂" "⊄" "⊊" "∝" "∊" "∍" "∥" "∦" "∷" "∺" "∻" 
"∽"
-             "∾" "≁" "≃" "≄" "≅" "≆" "≇" "≈" "≉" "≊" "≋" "≌" "≍" "≎" "≐" "≑" 
"≒"
-             "≓" "≔" "≕" "≖" "≗" "≘" "≙" "≚" "≛" "≜" "≝" "≞" "≟" "≣" "≦" "≧" 
"≨"
-             "≩" "≪" "≫" "≬" "≭" "≮" "≯" "≰" "≱" "≲" "≳" "≴" "≵" "≶" "≷" "≸" 
"≹"
-             "≺" "≻" "≼" "≽" "≾" "≿" "⊀" "⊁" "⊃" "⊅" "⊇" "⊉" "⊋" "⊏" "⊐" "⊑" 
"⊒"
-             "⊜" "⊩" "⊬" "⊮" "⊰" "⊱" "⊲" "⊳" "⊴" "⊵" "⊶" "⊷" "⋍" "⋐" "⋑" "⋕" 
"⋖"
-             "⋗" "⋘" "⋙" "⋚" "⋛" "⋜" "⋝" "⋞" "⋟" "⋠" "⋡" "⋢" "⋣" "⋤" "⋥" "⋦" 
"⋧"
-             "⋨" "⋩" "⋪" "⋫" "⋬" "⋭" "⋲" "⋳" "⋴" "⋵" "⋶" "⋷" "⋸" "⋹" "⋺" "⋻" 
"⋼"
-             "⋽" "⋾" "⋿" "⟈" "⟉" "⟒" "⦷" "⧀" "⧁" "⧡" "⧣" "⧤" "⧥" "⩦" "⩧" "⩪" 
"⩫"
-             "⩬" "⩭" "⩮" "⩯" "⩰" "⩱" "⩲" "⩳" "⩴" "⩵" "⩶" "⩷" "⩸" "⩹" "⩺" "⩻" 
"⩼"
-             "⩽" "⩾" "⩿" "⪀" "⪁" "⪂" "⪃" "⪄" "⪅" "⪆" "⪇" "⪈" "⪉" "⪊" "⪋" "⪌" 
"⪍"
-             "⪎" "⪏" "⪐" "⪑" "⪒" "⪓" "⪔" "⪕" "⪖" "⪗" "⪘" "⪙" "⪚" "⪛" "⪜" "⪝" 
"⪞"
-             "⪟" "⪠" "⪡" "⪢" "⪣" "⪤" "⪥" "⪦" "⪧" "⪨" "⪩" "⪪" "⪫" "⪬" "⪭" "⪮" 
"⪯"
-             "⪰" "⪱" "⪲" "⪳" "⪴" "⪵" "⪶" "⪷" "⪸" "⪹" "⪺" "⪻" "⪼" "⪽" "⪾" "⪿" 
"⫀"
-             "⫁" "⫂" "⫃" "⫄" "⫅" "⫆" "⫇" "⫈" "⫉" "⫊" "⫋" "⫌" "⫍" "⫎" "⫏" "⫐" 
"⫑"
-             "⫒" "⫓" "⫔" "⫕" "⫖" "⫗" "⫘" "⫙" "⫷" "⫸" "⫹" "⫺" "⊢" "⊣"
-             ;; pipe, colon
-             "|>" "<|" ":" ".."
-             ;; plus
-             "+" "-" "⊕" "⊖" "⊞" "⊟" ".+" ".-" "++" "|" "∪" "∨" "$" "⊔" "±" "∓"
-             "∔" "∸" "≂" "≏" "⊎" "⊻" "⊽" "⋎" "⋓" "⧺" "⧻" "⨈" "⨢" "⨣" "⨤" "⨥" 
"⨦"
-             "⨧" "⨨" "⨩" "⨪" "⨫" "⨬" "⨭" "⨮" "⨹" "⨺" "⩁" "⩂" "⩅" "⩊" "⩌" "⩏" 
"⩐"
-             "⩒" "⩔" "⩖" "⩗" "⩛" "⩝" "⩡" "⩢" "⩣"
-             ;; bitshift
-             "<<" ">>" ">>>" ".<<" ".>>" ".>>>"
-             ;; times
-             "*" "/" "./" "÷" ".÷" "%" "⋅" "∘" "×" ".%" ".*" "\\"
-             ".\\" "&" "∩" "∧" "⊗" "⊘" "⊙" "⊚" "⊛" "⊠" "⊡" "⊓" "∗" "∙" "∤" "⅋"
-             "≀" "⊼" "⋄" "⋆" "⋇" "⋉" "⋊" "⋋" "⋌" "⋏" "⋒" "⟑" "⦸" "⦼" "⦾" "⦿" 
"⧶"
-             "⧷" "⨇" "⨰" "⨱" "⨲" "⨳" "⨴" "⨵" "⨶" "⨷" "⨸" "⨻" "⨼" "⨽" "⩀" "⩃" 
"⩄"
-             "⩋" "⩍" "⩎" "⩑" "⩓" "⩕" "⩘" "⩚" "⩜" "⩞" "⩟" "⩠" "⫛" "⊍" "▷" "⨝" 
"⟕"
-             "⟖" "⟗"
-             ;; rational
-             "//" ".//"
-             ;; power
-             "^" ".^" "↑" "↓" "⇵" "⟰" "⟱" "⤈" "⤉" "⤊" "⤋" "⤒" "⤓" "⥉" "⥌" "⥍"
-             "⥏" "⥑" "⥔" "⥕" "⥘" "⥙" "⥜" "⥝" "⥠" "⥡" "⥣" "⥥" "⥮" "⥯" "↑" "↓"
-             ;; decl, dot
-             "::" "."))
-          (regexp-opt '(" #" " \n" "#" "\n"))))
+  (rx (or
+       ;; conditional
+       "?"
+       ;; assignment
+       "=" ":=" "+=" "-=" "*=" "/=" "//=" ".//=" ".*=" "./=" "\\=" ".\\="
+       "^=" ".^=" "÷=" ".÷=" "%=" ".%=" "|=" "&=" "$=" "=>" "<<=" ">>="
+       ">>>=" "~" ".+=" ".-="
+       ;; arrow
+       "--" "-->" "←" "→" "↔" "↚" "↛" "↠" "↣" "↦" "↮" "⇎" "⇏" "⇒" "⇔" "⇴"
+       "⇶" "⇷" "⇸" "⇹" "⇺" "⇻" "⇼" "⇽" "⇾" "⇿" "⟵" "⟶" "⟷" "⟷" "⟹"
+       "⟺" "⟻" "⟼" "⟽" "⟾" "⟿" "⤀" "⤁" "⤂" "⤃" "⤄" "⤅" "⤆" "⤇" "⤌"
+       "⤍" "⤎" "⤏" "⤐" "⤑" "⤔" "⤕" "⤖" "⤗" "⤘" "⤝" "⤞" "⤟" "⤠" "⥄" "⥅"
+       "⥆" "⥇" "⥈" "⥊" "⥋" "⥎" "⥐" "⥒" "⥓" "⥖" "⥗" "⥚" "⥛" "⥞" "⥟" "⥢"
+       "⥤" "⥦" "⥧" "⥨" "⥩" "⥪" "⥫" "⥬" "⥭" "⥰" "⧴" "⬱" "⬰" "⬲" "⬳" "⬴"
+       "⬵" "⬶" "⬷" "⬸" "⬹" "⬺" "⬻" "⬼" "⬽" "⬾" "⬿" "⭀" "⭁" "⭂" "⭃" "⭄"
+       "⭇" "⭈" "⭉" "⭊" "⭋" "⭌" "←" "→"
+       ;; or and and
+       "&&" "||"
+       ;; comparison
+       ">" "<" ">=" "≥" "<=" "≤" "==" "===" "≡" "!=" "≠" "!==" "≢" ".>"
+       ".<" ".>=" ".≥" ".<=" ".≤" ".==" ".!=" ".≠" ".=" ".!" "<:" ">:" "∈"
+       "∉" "∋" "∌" "⊆" "⊈" "⊂" "⊄" "⊊" "∝" "∊" "∍" "∥" "∦" "∷" "∺" "∻" "∽"
+       "∾" "≁" "≃" "≄" "≅" "≆" "≇" "≈" "≉" "≊" "≋" "≌" "≍" "≎" "≐" "≑" "≒"
+       "≓" "≔" "≕" "≖" "≗" "≘" "≙" "≚" "≛" "≜" "≝" "≞" "≟" "≣" "≦" "≧" "≨"
+       "≩" "≪" "≫" "≬" "≭" "≮" "≯" "≰" "≱" "≲" "≳" "≴" "≵" "≶" "≷" "≸" "≹"
+       "≺" "≻" "≼" "≽" "≾" "≿" "⊀" "⊁" "⊃" "⊅" "⊇" "⊉" "⊋" "⊏" "⊐" "⊑" "⊒"
+       "⊜" "⊩" "⊬" "⊮" "⊰" "⊱" "⊲" "⊳" "⊴" "⊵" "⊶" "⊷" "⋍" "⋐" "⋑" "⋕" "⋖"
+       "⋗" "⋘" "⋙" "⋚" "⋛" "⋜" "⋝" "⋞" "⋟" "⋠" "⋡" "⋢" "⋣" "⋤" "⋥" "⋦" "⋧"
+       "⋨" "⋩" "⋪" "⋫" "⋬" "⋭" "⋲" "⋳" "⋴" "⋵" "⋶" "⋷" "⋸" "⋹" "⋺" "⋻" "⋼"
+       "⋽" "⋾" "⋿" "⟈" "⟉" "⟒" "⦷" "⧀" "⧁" "⧡" "⧣" "⧤" "⧥" "⩦" "⩧" "⩪" "⩫"
+       "⩬" "⩭" "⩮" "⩯" "⩰" "⩱" "⩲" "⩳" "⩴" "⩵" "⩶" "⩷" "⩸" "⩹" "⩺" "⩻" "⩼"
+       "⩽" "⩾" "⩿" "⪀" "⪁" "⪂" "⪃" "⪄" "⪅" "⪆" "⪇" "⪈" "⪉" "⪊" "⪋" "⪌" "⪍"
+       "⪎" "⪏" "⪐" "⪑" "⪒" "⪓" "⪔" "⪕" "⪖" "⪗" "⪘" "⪙" "⪚" "⪛" "⪜" "⪝" "⪞"
+       "⪟" "⪠" "⪡" "⪢" "⪣" "⪤" "⪥" "⪦" "⪧" "⪨" "⪩" "⪪" "⪫" "⪬" "⪭" "⪮" "⪯"
+       "⪰" "⪱" "⪲" "⪳" "⪴" "⪵" "⪶" "⪷" "⪸" "⪹" "⪺" "⪻" "⪼" "⪽" "⪾" "⪿" "⫀"
+       "⫁" "⫂" "⫃" "⫄" "⫅" "⫆" "⫇" "⫈" "⫉" "⫊" "⫋" "⫌" "⫍" "⫎" "⫏" "⫐" "⫑"
+       "⫒" "⫓" "⫔" "⫕" "⫖" "⫗" "⫘" "⫙" "⫷" "⫸" "⫹" "⫺" "⊢" "⊣"
+       ;; pipe, colon
+       "|>" "<|" ":" ".."
+       ;; plus
+       "+" "-" "⊕" "⊖" "⊞" "⊟" ".+" ".-" "++" "|" "∪" "∨" "$" "⊔" "±" "∓"
+       "∔" "∸" "≂" "≏" "⊎" "⊻" "⊽" "⋎" "⋓" "⧺" "⧻" "⨈" "⨢" "⨣" "⨤" "⨥" "⨦"
+       "⨧" "⨨" "⨩" "⨪" "⨫" "⨬" "⨭" "⨮" "⨹" "⨺" "⩁" "⩂" "⩅" "⩊" "⩌" "⩏" "⩐"
+       "⩒" "⩔" "⩖" "⩗" "⩛" "⩝" "⩡" "⩢" "⩣"
+       ;; bitshift
+       "<<" ">>" ">>>" ".<<" ".>>" ".>>>"
+       ;; times
+       "*" "/" "./" "÷" ".÷" "%" "⋅" "∘" "×" ".%" ".*" "\\"
+       ".\\" "&" "∩" "∧" "⊗" "⊘" "⊙" "⊚" "⊛" "⊠" "⊡" "⊓" "∗" "∙" "∤" "⅋"
+       "≀" "⊼" "⋄" "⋆" "⋇" "⋉" "⋊" "⋋" "⋌" "⋏" "⋒" "⟑" "⦸" "⦼" "⦾" "⦿" "⧶"
+       "⧷" "⨇" "⨰" "⨱" "⨲" "⨳" "⨴" "⨵" "⨶" "⨷" "⨸" "⨻" "⨼" "⨽" "⩀" "⩃" "⩄"
+       "⩋" "⩍" "⩎" "⩑" "⩓" "⩕" "⩘" "⩚" "⩜" "⩞" "⩟" "⩠" "⫛" "⊍" "▷" "⨝" "⟕"
+       "⟖" "⟗"
+       ;; rational
+       "//" ".//"
+       ;; power
+       "^" ".^" "↑" "↓" "⇵" "⟰" "⟱" "⤈" "⤉" "⤊" "⤋" "⤒" "⤓" "⥉" "⥌" "⥍"
+       "⥏" "⥑" "⥔" "⥕" "⥘" "⥙" "⥜" "⥝" "⥠" "⥡" "⥣" "⥥" "⥮" "⥯" "↑" "↓"
+       ;; decl, dot
+       "::" ".")
+      (* blank)
+      (or eol ?#)))
 
 (defconst julia-unquote-regex
   "\\(\\s(\\|\\s-\\|-\\|[,%=<>\\+*/?&|!\\^~\\\\;:]\\|^\\)\\($[a-zA-Z0-9_]+\\)")
@@ -255,7 +259,7 @@
 (defconst julia-keyword-regex
   (regexp-opt
    '("if" "else" "elseif" "while" "for" "begin" "end" "quote"
-     "try" "catch" "return" "local" "function" "macro" "ccall"
+     "try" "catch" "return" "local" "function" "macro"
      "finally" "break" "continue" "global" "where"
      "module" "using" "import" "export" "const" "let" "do"
      "baremodule"
@@ -280,9 +284,11 @@
    (cons julia-macro-regex ''julia-macro-face)
    (cons
     (regexp-opt
-     '("true" "false" "C_NULL" "Inf" "NaN" "Inf32" "NaN32" "nothing" "undef" 
"missing")
+     ;; constants defined in Core plus true/false
+     '("true" "false" "Cvoid" "Inf" "NaN" "Inf32" "NaN32" "nothing" "undef" 
"missing")
      'symbols)
     'font-lock-constant-face)
+   (cons "ccall" 'font-lock-builtin-face)
    (list julia-unquote-regex 2 'font-lock-constant-face)
    (list julia-forloop-in-regex 1 'font-lock-keyword-face)
    (list julia--forloop-=-regex 1 'font-lock-keyword-face)
@@ -312,25 +318,9 @@
 (defconst julia-block-end-keywords
   (list "end" "else" "elseif" "catch" "finally"))
 
-(defconst julia-syntax-propertize-function
-  (syntax-propertize-rules
-   ;; triple-quoted strings are a single string rather than 3
-   ((rx (group ?\") ?\" (group ?\"))
-    ;; First " starts a string if not already inside a string (or comment)
-    (1 (let ((ppss (save-excursion (syntax-ppss (match-beginning 0)))))
-         (unless (or (nth 3 ppss) (nth 4 ppss))
-           (string-to-syntax "|"))))
-    ;; Last " ends a string if already inside a string
-    (2 (and (nth 3 (save-excursion (syntax-ppss (match-beginning 0))))
-            (string-to-syntax "|"))))
-   ;; backslash acts as an operator if it's not inside a string
-   ("\\\\"
-    (0 (unless (nth 3 (save-excursion (syntax-ppss (match-beginning 0))))
-         (string-to-syntax "."))))
-   (julia-char-regex
-    (1 "\"")                    ; Treat ' as a string delimiter.
-    (2 ".")                     ; Don't highlight anything between.
-    (3 "\"")))) ; Treat the last " in """ as a string delimiter.
+(defsubst julia-syntax-comment-or-string-p (&optional syntax-ppss)
+  "Return non-nil if SYNTAX-PPSS is inside string or comment."
+  (nth 8 (or syntax-ppss (syntax-ppss))))
 
 (defun julia-in-comment (&optional syntax-ppss)
   "Return non-nil if point is inside a comment using SYNTAX-PPSS.
@@ -343,6 +333,49 @@ Note this is Emacs' notion of what is highlighted as a 
string.
 As a result, it is true inside \"foo\", `foo` and 'f'."
   (nth 3 (or syntax-ppss (syntax-ppss))))
 
+(defconst julia-syntax-propertize-function
+  (syntax-propertize-rules
+   ;; triple-quoted strings are a single string rather than 3
+   ("\"\"\""
+    (0 (ignore (julia-syntax-stringify))))
+   ;; same with triple-quoted backticks
+   ("```"
+    (0 (ignore (julia-syntax-stringify))))
+   ;; backslash acts as an operator if it's not inside a string
+   ("\\\\"
+    (0 (unless (julia-in-string
+                (save-excursion (syntax-ppss (match-beginning 0))))
+         (string-to-syntax "."))))
+   (julia-char-regex
+    ;; treat ' in 'c' as string-delimiter
+    (1 "\"")
+    (2 "\""))))
+
+(defun julia-syntax-stringify ()
+  "Put `syntax-table' property correctly on triple-quoted strings and cmds."
+  (let* ((ppss (save-excursion (syntax-ppss (match-beginning 0))))
+         (string-open (and (not (nth 4 ppss)) (nth 8 ppss))))
+    (cond
+     ;; this set of quotes delimit the start of string/cmd
+     ((not string-open)
+      (put-text-property (match-beginning 0) (1+ (match-beginning 0))
+                         'syntax-table (string-to-syntax "|")))
+     ;; this set of quotes closes the current string/cmd
+     ((and
+       ;; check that """ closes """ and ``` closes ```
+       (eq (char-before) (char-after string-open))
+       ;; check that triple quote isn't escaped by odd number of backslashes
+       (let ((i 0))
+         (while (and (< (point-min) (- (match-beginning 0) i))
+                     (eq (char-before (- (match-beginning 0) i)) ?\\))
+           (setq i (1+ i)))
+         (cl-evenp i)))
+      (put-text-property (1- (match-end 0)) (match-end 0)
+                         'syntax-table (string-to-syntax "|")))
+     ;; Put point after (match-beginning 0) to account for possibility
+     ;; of overlapping triple-quotes with first escaped
+     ((backward-char 2)))))
+
 (defun julia-in-brackets ()
   "Return non-nil if point is inside square brackets."
   (let ((start-pos (point))
@@ -353,7 +386,7 @@ As a result, it is true inside \"foo\", `foo` and 'f'."
 
       (while (< (point) start-pos)
         ;; Don't count [ or ] inside strings, characters or comments.
-        (unless (or (julia-in-string) (julia-in-comment))
+        (unless (julia-syntax-comment-or-string-p)
 
           (when (looking-at (rx "["))
             (cl-incf open-count))
@@ -369,7 +402,7 @@ As a result, it is true inside \"foo\", `foo` and 'f'."
   "Return the word at point if it matches any keyword in KW-LIST.
 KW-LIST is a list of strings.  The word at point is not considered
 a keyword if used as a field name, X.word, or quoted, :word."
-  (and (or (= (point) 1)
+  (and (or (bobp)
           (and (not (equal (char-before (point)) ?.))
                (not (equal (char-before (point)) ?:))))
        (not (looking-at "("))           ; handle "function(" when on (
@@ -399,7 +432,7 @@ symbol, gives up when this is not true."
       (while (and (not done) (< (point-min) (point)))
         (julia-safe-backward-sexp)
         (cond
-         ((looking-at (rx (or "import" "export" "using")))
+         ((looking-at (regexp-opt (list "import" "export" "using")))
           (setf done (point)))
          ((looking-at (rx (group (* (or word (syntax symbol)))) (0+ space) 
":"))
           (if module
@@ -407,6 +440,8 @@ symbol, gives up when this is not true."
             (setf module (match-string-no-properties 1))))
          ((looking-at (rx (* (or word (syntax symbol))) (0+ space) ","))
           (when module (setf done 'broken)))
+         ((looking-at (rx (* (or word (syntax symbol))) "."))
+          (setf module (concat (match-string-no-properties 0) module)))
          (t (setf done 'broken)))))
     (if (eq done 'broken)
         nil
@@ -438,13 +473,19 @@ Do not move back beyond MIN."
     (and pos
         (progn
           (goto-char pos)
-          (+ julia-indent-offset (current-indentation))))))
+          (+ julia-indent-offset (julia-block-open-indentation))))))
 
-(defsubst julia--safe-backward-char ()
-  "Move back one character, but don't error if we're at the
-beginning of the buffer."
-  (unless (eq (point) (point-min))
-    (backward-char)))
+(defun julia-block-open-indentation ()
+  "Get the current indentation or the start of a parenthetical block."
+  (save-excursion
+    (save-restriction
+      ;; narrow to one line to only search syntax on that line
+      (narrow-to-region (line-beginning-position) (line-end-position))
+        (condition-case nil
+            (progn
+              (backward-up-list)
+              (1+ (current-column)))
+          (error (current-indentation))))))
 
 (defcustom julia-max-block-lookback 20000
   "When indenting, don't look back more than this many characters
@@ -453,8 +494,7 @@ to see if there are unclosed blocks.
 This variable has a small effect on indent performance if set
 too high, but stops indenting in the middle of long blocks if set
 too low."
-  :type 'integer
-  :group 'julia)
+  :type 'integer)
 
 (defun julia-paren-indent ()
   "Return the column of the text following the innermost
@@ -516,6 +556,12 @@ the (possibly narrowed) buffer, so there is nowhere else 
to go."
          (t
           (throw 'result 0)))))))
 
+(defun julia--hanging-operator-p ()
+  "Return t if current line ends with a hanging operator."
+  (and (re-search-forward julia-hanging-operator-regexp (line-end-position) t)
+       (not (julia-syntax-comment-or-string-p
+             (save-excursion (syntax-ppss (match-beginning 0)))))))
+
 (defun julia-indent-hanging ()
   "Calculate indentation for lines that follow \"hanging\"
 operators (operators that end the previous line) as defined in
@@ -528,9 +574,9 @@ only comments."
     (save-excursion
       (when (> (julia-prev-line-skip-blank-or-comment) 0)
         (setq prev-indent (current-indentation))
-        (when (looking-at-p julia-hanging-operator-regexp)
+        (when (julia--hanging-operator-p)
           (if (and (> (julia-prev-line-skip-blank-or-comment) 0)
-                   (looking-at-p julia-hanging-operator-regexp))
+                   (julia--hanging-operator-p))
               ;; two preceding hanging operators => indent same as line
               ;; above
               prev-indent
@@ -565,27 +611,27 @@ meaning always increase indent on TAB and decrease on 
S-TAB."
       ;; note: if this first function returns nil the beginning of the line
       ;; cannot be in a string
       (julia-indent-in-string)
-      ;; If we're inside an open paren, indent to line up arguments. After 
this,
-      ;; we cannot be inside parens which includes brackets
-      (julia-paren-indent)
       ;; indent due to hanging operators (lines ending in an operator)
       (julia-indent-hanging)
       ;; indent for import and export
       (julia-indent-import-export-using)
-      ;; Indent according to how many nested blocks we are in.
-      (save-excursion
-        (beginning-of-line)
-        ;; jump out of any comments
-        (let ((state (syntax-ppss)))
-          (when (nth 4 state)
-            (goto-char (nth 8 state))))
-        (forward-to-indentation 0)
-        (let ((endtok (julia-at-keyword julia-block-end-keywords))
-              (last-open-block (julia-last-open-block (- (point) 
julia-max-block-lookback))))
-          (max 0 (+ (or last-open-block 0)
-                    (if (or endtok
-                            (julia-at-keyword 
julia-block-start-keywords-no-indent))
-                        (- julia-indent-offset) 0)))))))
+      ;; use julia-paren-indent along with block indentation
+      (let ((paren-indent (or (julia-paren-indent) 0)))
+        ;; Indent according to how many nested blocks we are in.
+        (save-excursion
+          (beginning-of-line)
+          ;; jump out of any comments
+          (let ((state (syntax-ppss)))
+            (when (nth 4 state)
+              (goto-char (nth 8 state))))
+          (forward-to-indentation 0)
+          (let ((endtok (julia-at-keyword julia-block-end-keywords))
+                (last-open-block (julia-last-open-block (- (point) 
julia-max-block-lookback))))
+            (max paren-indent (- (or last-open-block paren-indent)
+                                 ;; subtract indentation if we're at the end 
of a block
+                                 (if (or endtok
+                                         (julia-at-keyword 
julia-block-start-keywords-no-indent))
+                                     julia-indent-offset 0))))))))
     ;; Point is now at the beginning of indentation, restore it
     ;; to its original position (relative to indentation).
     (when (>= point-offset 0)
@@ -608,10 +654,6 @@ TYPE can be `comment', `string' or `paren'."
      ((nth 8 ppss) (if (nth 4 ppss) 'comment 'string))
      ((nth 1 ppss) 'paren))))
 
-(defsubst julia-syntax-comment-or-string-p (&optional syntax-ppss)
-  "Return non-nil if SYNTAX-PPSS is inside string or comment."
-  (nth 8 (or syntax-ppss (syntax-ppss))))
-
 (defun julia-looking-at-beginning-of-defun (&optional syntax-ppss)
   "Check if point is at `beginning-of-defun' using SYNTAX-PPSS."
   (and (not (julia-syntax-comment-or-string-p (or syntax-ppss (syntax-ppss))))
@@ -724,6 +766,7 @@ Return nil if point is not in a function, otherwise point."
 ;;;###autoload
 (define-derived-mode julia-mode prog-mode "Julia"
   "Major mode for editing julia code."
+  :group 'julia
   (set-syntax-table julia-mode-syntax-table)
   (setq-local comment-start "# ")
   (setq-local comment-start-skip "#+\\s-*")
@@ -774,7 +817,7 @@ strings."
 ;; (add-hook 'julia-mode-hook 'julia-math-mode)
 ;; (add-hook 'inferior-julia-mode-hook 'julia-math-mode)
 
-(when (require 'latex nil t)
+(when (featurep 'latex)
   (declare-function LaTeX-math-abbrev-prefix "latex")
 
   (defun julia-math-insert (s)
@@ -829,6 +872,10 @@ following commands are defined:
       (pop-to-buffer-same-window "*Julia*")
       (inferior-julia-mode)))
 
+(make-obsolete 'inferior-julia
+               "REPL modes are now provided by various third-party packages, 
this will be removed."
+               "2021-08-30")
+
 (defun inferior-julia--initialize ()
     "Helper function to initialize `inferior-julia'."
     (setq comint-use-prompt-regexp t))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]