Bump the go-modules-updates group across 1 directory with 11 updates

Bumps the go-modules-updates group with 11 updates in the /backend directory:

| Package | From | To |
| --- | --- | --- |
| [github.com/PuerkitoBio/goquery](https://github.com/PuerkitoBio/goquery) | `1.10.2` | `1.11.0` |
| [github.com/alecthomas/chroma/v2](https://github.com/alecthomas/chroma) | `2.15.0` | `2.20.0` |
| [github.com/go-chi/chi/v5](https://github.com/go-chi/chi) | `5.2.1` | `5.2.3` |
| [github.com/go-chi/cors](https://github.com/go-chi/cors) | `1.2.1` | `1.2.2` |
| [github.com/go-pkgz/jrpc](https://github.com/go-pkgz/jrpc) | `0.3.1` | `0.4.0` |
| [github.com/go-pkgz/lgr](https://github.com/go-pkgz/lgr) | `0.12.0` | `0.12.1` |
| [github.com/go-pkgz/rest](https://github.com/go-pkgz/rest) | `1.20.3` | `1.20.4` |
| [github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt) | `5.2.2` | `5.3.0` |
| [github.com/stretchr/testify](https://github.com/stretchr/testify) | `1.10.0` | `1.11.1` |
| [go.etcd.io/bbolt](https://github.com/etcd-io/bbolt) | `1.4.0` | `1.4.3` |
| [golang.org/x/image](https://github.com/golang/image) | `0.26.0` | `0.33.0` |

Updates `github.com/PuerkitoBio/goquery` from 1.10.2 to 1.11.0
- [Release notes](https://github.com/PuerkitoBio/goquery/releases)
- [Commits](https://github.com/PuerkitoBio/goquery/compare/v1.10.2...v1.11.0)

Updates `github.com/alecthomas/chroma/v2` from 2.15.0 to 2.20.0
- [Release notes](https://github.com/alecthomas/chroma/releases)
- [Commits](https://github.com/alecthomas/chroma/compare/v2.15.0...v2.20.0)

Updates `github.com/go-chi/chi/v5` from 5.2.1 to 5.2.3
- [Release notes](https://github.com/go-chi/chi/releases)
- [Changelog](https://github.com/go-chi/chi/blob/master/CHANGELOG.md)
- [Commits](https://github.com/go-chi/chi/compare/v5.2.1...v5.2.3)

Updates `github.com/go-chi/cors` from 1.2.1 to 1.2.2
- [Release notes](https://github.com/go-chi/cors/releases)
- [Commits](https://github.com/go-chi/cors/compare/v1.2.1...v1.2.2)

Updates `github.com/go-pkgz/jrpc` from 0.3.1 to 0.4.0
- [Release notes](https://github.com/go-pkgz/jrpc/releases)
- [Commits](https://github.com/go-pkgz/jrpc/compare/v0.3.1...v0.4.0)

Updates `github.com/go-pkgz/lgr` from 0.12.0 to 0.12.1
- [Release notes](https://github.com/go-pkgz/lgr/releases)
- [Commits](https://github.com/go-pkgz/lgr/compare/v0.12.0...v0.12.1)

Updates `github.com/go-pkgz/rest` from 1.20.3 to 1.20.4
- [Release notes](https://github.com/go-pkgz/rest/releases)
- [Commits](https://github.com/go-pkgz/rest/compare/v1.20.3...v1.20.4)

Updates `github.com/golang-jwt/jwt/v5` from 5.2.2 to 5.3.0
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Commits](https://github.com/golang-jwt/jwt/compare/v5.2.2...v5.3.0)

Updates `github.com/stretchr/testify` from 1.10.0 to 1.11.1
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.10.0...v1.11.1)

Updates `go.etcd.io/bbolt` from 1.4.0 to 1.4.3
- [Release notes](https://github.com/etcd-io/bbolt/releases)
- [Commits](https://github.com/etcd-io/bbolt/compare/v1.4.0...v1.4.3)

Updates `golang.org/x/image` from 0.26.0 to 0.33.0
- [Commits](https://github.com/golang/image/compare/v0.26.0...v0.33.0)

---
updated-dependencies:
- dependency-name: github.com/PuerkitoBio/goquery
  dependency-version: 1.11.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-modules-updates
- dependency-name: github.com/alecthomas/chroma/v2
  dependency-version: 2.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-modules-updates
- dependency-name: github.com/go-chi/chi/v5
  dependency-version: 5.2.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-modules-updates
- dependency-name: github.com/go-chi/cors
  dependency-version: 1.2.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-modules-updates
- dependency-name: github.com/go-pkgz/jrpc
  dependency-version: 0.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-modules-updates
- dependency-name: github.com/go-pkgz/lgr
  dependency-version: 0.12.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-modules-updates
- dependency-name: github.com/go-pkgz/rest
  dependency-version: 1.20.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-modules-updates
- dependency-name: github.com/golang-jwt/jwt/v5
  dependency-version: 5.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-modules-updates
- dependency-name: github.com/stretchr/testify
  dependency-version: 1.11.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-modules-updates
- dependency-name: go.etcd.io/bbolt
  dependency-version: 1.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: go-modules-updates
- dependency-name: golang.org/x/image
  dependency-version: 0.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: go-modules-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2025-12-03 18:17:46 -06:00
committed by Umputun
parent d925584af8
commit 6d8a0c783b
197 changed files with 4874 additions and 5762 deletions
+10 -14
View File
@@ -3,27 +3,23 @@ module github.com/umputun/remark42/memory_store
go 1.25
require (
github.com/go-pkgz/jrpc v0.3.1
github.com/go-pkgz/lgr v0.12.0
github.com/go-pkgz/jrpc v0.4.0
github.com/go-pkgz/lgr v0.12.1
github.com/jessevdk/go-flags v1.6.1
github.com/stretchr/testify v1.10.0
github.com/stretchr/testify v1.11.1
github.com/umputun/remark42/backend v1.1000.0
)
require (
github.com/Depado/bfchroma/v2 v2.0.0 // indirect
github.com/PuerkitoBio/goquery v1.10.2 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/alecthomas/chroma/v2 v2.15.0 // indirect
github.com/PuerkitoBio/goquery v1.11.0 // indirect
github.com/alecthomas/chroma/v2 v2.20.0 // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/didip/tollbooth/v8 v8.0.1 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/go-chi/chi/v5 v5.2.1 // indirect
github.com/go-chi/render v1.0.3 // indirect
github.com/go-pkgz/expirable-cache/v3 v3.0.0 // indirect
github.com/go-pkgz/rest v1.20.3 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/go-pkgz/rest v1.20.4 // indirect
github.com/go-pkgz/routegroup v1.6.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -33,9 +29,9 @@ require (
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
go.etcd.io/bbolt v1.4.0 // indirect
go.etcd.io/bbolt v1.4.3 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/image v0.26.0 // indirect
golang.org/x/image v0.33.0 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sys v0.38.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
+24 -34
View File
@@ -1,15 +1,13 @@
github.com/Depado/bfchroma/v2 v2.0.0 h1:IRpN9BPkNwEpR6w1ectIcNWOuhDSLx+8f1pn83fzxx8=
github.com/Depado/bfchroma/v2 v2.0.0/go.mod h1:wFwW/Pw8Tnd0irzgO9Zxtxgzp3aPS8qBWlyadxujxmw=
github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8=
github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw=
github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA=
github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg=
github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM=
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
@@ -17,22 +15,16 @@ github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd3
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/didip/tollbooth/v8 v8.0.1 h1:VAAapTo1t4Bn6bbpcHjuovwoa9u3JH++wgjbpWv+rB8=
github.com/didip/tollbooth/v8 v8.0.1/go.mod h1:oEd9l+ep373d7DmvKLc0a5gasPOev2mTewi6KPQBGJ4=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-pkgz/expirable-cache/v3 v3.0.0 h1:u3/gcu3sabLYiTCevoRKv+WzjIn5oo7P8XtiXBeRDLw=
github.com/go-pkgz/expirable-cache/v3 v3.0.0/go.mod h1:2OQiDyEGQalYecLWmXprm3maPXeVb5/6/X7yRPYTzec=
github.com/go-pkgz/jrpc v0.3.1 h1:jRxnO5ppOookkL9PuOWw/IloevmzqbsKaGImTR3iALQ=
github.com/go-pkgz/jrpc v0.3.1/go.mod h1:DJg1RfhwvJpVT3YXtk8LxowB7DN5jUoZ3U4MbHnm76M=
github.com/go-pkgz/lgr v0.12.0 h1:uoSCLdiMocZDa+L66DavHG5UIkOJvWKOVqt6sNQllw0=
github.com/go-pkgz/lgr v0.12.0/go.mod h1:A4AxjOthFVFK6jRnVYMeusno5SeDAxcLVHd0kI/lN/Y=
github.com/go-pkgz/rest v1.20.3 h1:oGGfM8XTnvwek29q1OAhcI1nkKKOpurRFApBiYH44Fk=
github.com/go-pkgz/rest v1.20.3/go.mod h1:NC2xNN/y1rIs0PY13FowKoH8rk9RhJNJ0tTbkBg8Yks=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/go-pkgz/jrpc v0.4.0 h1:oD7xiGrzDkndkuCjeHGugQXxbggLSV7O1QmHhoc5pYY=
github.com/go-pkgz/jrpc v0.4.0/go.mod h1:JFoY3bRjRyx4M3CbEVDFQStMB1m2gmQ7OjqFK7q3kOo=
github.com/go-pkgz/lgr v0.12.1 h1:8GVfG2rSARq3Eaj5PP158rtBR2LHVGkwioIkQBGbvKg=
github.com/go-pkgz/lgr v0.12.1/go.mod h1:A4AxjOthFVFK6jRnVYMeusno5SeDAxcLVHd0kI/lN/Y=
github.com/go-pkgz/rest v1.20.4 h1:8ufcP1IqoDhCvIFdXPtvyX4HSS16SM6THBe2a6L0/kg=
github.com/go-pkgz/rest v1.20.4/go.mod h1:2/LEZGndSxpVvExsMn48AjUgiTn6kILqjpoaRnl62JU=
github.com/go-pkgz/routegroup v1.6.0 h1:44XHZgF6JIIldRlv+zjg6SygULASmjifnfIQjwCT0e4=
github.com/go-pkgz/routegroup v1.6.0/go.mod h1:Pmu04fhgWhRtBMIJ8HXppnnzOPjnL/IEPBIdO2zmeqg=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
@@ -41,8 +33,6 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4=
@@ -61,11 +51,11 @@ github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
@@ -74,8 +64,8 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
@@ -99,8 +89,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+2 -2
View File
@@ -178,8 +178,8 @@ BKT
assert.Equal(t, http.StatusOK, resp.StatusCode)
b, err := io.ReadAll(resp.Body)
assert.NoError(t, err)
assert.Equal(t, `<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="nx">aa</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span><span class="k">return</span> <span class="mi">0</span><span class="p">}</span>
</span></span></code></pre>`, string(b))
assert.Equal(t, `<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="nx">aa</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">}</span><span class="w">
</span></span></span></code></pre>`, string(b))
assert.NoError(t, resp.Body.Close())
}
+2 -2
View File
@@ -43,8 +43,8 @@ func TestFormatter_FormatText(t *testing.T) {
{`no_smartpants «quoted» text`, "<p>no_smartpants «quoted» text</p>\n!converted", "French guillemets without smartpants"},
{`«quoted» text`, "<p>«quoted» text</p>\n!converted", "French guillemets with smartpants"},
{"smth\n```go\nfunc main(aa string) int {return 0}\n```", `<p>smth</p>
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">(</span><span class="nx">aa</span> <span class="kt">string</span><span class="p">)</span> <span class="kt">int</span> <span class="p">{</span><span class="k">return</span> <span class="mi">0</span><span class="p">}</span>
</span></span></code></pre>!converted`, "code with language"},
<pre class="chroma"><code><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">main</span><span class="p">(</span><span class="nx">aa</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="p">{</span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">}</span><span class="w">
</span></span></span></code></pre>!converted`, "code with language"},
{"```\ntest_code\n```", `<pre class="chroma"><code><span class="line"><span class="cl">test_code
</span></span></code></pre>!converted`, "code without language"},
}
+13 -15
View File
@@ -4,21 +4,21 @@ go 1.25
require (
github.com/Depado/bfchroma/v2 v2.0.0
github.com/PuerkitoBio/goquery v1.10.2
github.com/alecthomas/chroma/v2 v2.15.0
github.com/PuerkitoBio/goquery v1.11.0
github.com/alecthomas/chroma/v2 v2.20.0
github.com/didip/tollbooth/v7 v7.0.2
github.com/didip/tollbooth_chi v0.0.0-20220719025231-d662a7f6928f
github.com/go-chi/chi/v5 v5.2.1
github.com/go-chi/cors v1.2.1
github.com/go-chi/chi/v5 v5.2.3
github.com/go-chi/cors v1.2.2
github.com/go-pkgz/auth/v2 v2.0.1-0.20250415030422-4f9f2c5e3b0d
github.com/go-pkgz/jrpc v0.3.1
github.com/go-pkgz/jrpc v0.4.0
github.com/go-pkgz/lcw/v2 v2.0.0
github.com/go-pkgz/lgr v0.12.0
github.com/go-pkgz/lgr v0.12.1
github.com/go-pkgz/notify v1.2.0
github.com/go-pkgz/repeater v1.2.0
github.com/go-pkgz/rest v1.20.3
github.com/go-pkgz/rest v1.20.4
github.com/go-pkgz/syncs v1.3.2
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/google/uuid v1.6.0
github.com/gorilla/feeds v1.2.0
github.com/hashicorp/go-multierror v1.1.1
@@ -28,29 +28,27 @@ require (
github.com/rs/xid v1.6.0
github.com/russross/blackfriday/v2 v2.1.0
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stretchr/testify v1.10.0
go.etcd.io/bbolt v1.4.0
github.com/stretchr/testify v1.11.1
go.etcd.io/bbolt v1.4.3
go.uber.org/goleak v1.3.0
golang.org/x/crypto v0.45.0
golang.org/x/image v0.26.0
golang.org/x/image v0.33.0
golang.org/x/net v0.47.0
)
require (
cloud.google.com/go/compute/metadata v0.6.0 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dghubble/oauth1 v0.7.3 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/didip/tollbooth/v8 v8.0.1 // indirect
github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/go-chi/render v1.0.3 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/go-oauth2/oauth2/v4 v4.5.3 // indirect
github.com/go-pkgz/email v0.5.0 // indirect
github.com/go-pkgz/expirable-cache/v3 v3.0.0 // indirect
github.com/go-pkgz/routegroup v1.6.0 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
+28 -30
View File
@@ -3,16 +3,16 @@ cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
github.com/Depado/bfchroma/v2 v2.0.0 h1:IRpN9BPkNwEpR6w1ectIcNWOuhDSLx+8f1pn83fzxx8=
github.com/Depado/bfchroma/v2 v2.0.0/go.mod h1:wFwW/Pw8Tnd0irzgO9Zxtxgzp3aPS8qBWlyadxujxmw=
github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8=
github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU=
github.com/PuerkitoBio/goquery v1.11.0 h1:jZ7pwMQXIITcUXNH83LLk+txlaEy6NVOfTuP43xxfqw=
github.com/PuerkitoBio/goquery v1.11.0/go.mod h1:wQHgxUOU3JGuj3oD/QFfxUdlzW6xPHfqyHre6VMY4DQ=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw=
github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA=
github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg=
github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE=
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis/v2 v2.31.1 h1:7XAt0uUg3DtwEKW5ZAGa+K7FZV2DdKQo5K/6TTnfX8Y=
@@ -40,12 +40,10 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
github.com/didip/tollbooth/v7 v7.0.0/go.mod h1:VZhDSGl5bDSPj4wPsih3PFa4Uh9Ghv8hgacaTm5PRT4=
github.com/didip/tollbooth/v7 v7.0.2 h1:WYEfusYI6g64cN0qbZgekDrYfuYBZjUZd5+RlWi69p4=
github.com/didip/tollbooth/v7 v7.0.2/go.mod h1:RtRYfEmFGX70+ike5kSndSvLtQ3+F2EAmTI4Un/VXNc=
github.com/didip/tollbooth/v8 v8.0.1 h1:VAAapTo1t4Bn6bbpcHjuovwoa9u3JH++wgjbpWv+rB8=
github.com/didip/tollbooth/v8 v8.0.1/go.mod h1:oEd9l+ep373d7DmvKLc0a5gasPOev2mTewi6KPQBGJ4=
github.com/didip/tollbooth_chi v0.0.0-20220719025231-d662a7f6928f h1:jtKwihcLmUC9BAhoJ9adCUqdSSZcOdH2KL7mPTUm2aw=
github.com/didip/tollbooth_chi v0.0.0-20220719025231-d662a7f6928f/go.mod h1:q9C80dnsuVRP2dAskjnXRNWdUJqtGgwG9wNrzt0019s=
github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
@@ -53,12 +51,10 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8=
github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-oauth2/oauth2/v4 v4.5.3 h1:lQt7O9KOnu/v4awe166FH7+p8tFUXQyR+no6nctAKU0=
github.com/go-oauth2/oauth2/v4 v4.5.3/go.mod h1:ryzb7zr8fdQBlciD0+tcnEWeOok5B0J8V/DniwYqQ2k=
github.com/go-pkgz/auth/v2 v2.0.1-0.20250415030422-4f9f2c5e3b0d h1:xyTp7JRaHy3/ttpcNiJO/YzxENZcvxcZL8iE3QfssnY=
@@ -68,26 +64,28 @@ github.com/go-pkgz/email v0.5.0/go.mod h1:BdxglsQnymzhfdbnncEE72a6DrucZHy6I+42LK
github.com/go-pkgz/expirable-cache v0.1.0/go.mod h1:GTrEl0X+q0mPNqN6dtcQXksACnzCBQ5k/k1SwXJsZKs=
github.com/go-pkgz/expirable-cache/v3 v3.0.0 h1:u3/gcu3sabLYiTCevoRKv+WzjIn5oo7P8XtiXBeRDLw=
github.com/go-pkgz/expirable-cache/v3 v3.0.0/go.mod h1:2OQiDyEGQalYecLWmXprm3maPXeVb5/6/X7yRPYTzec=
github.com/go-pkgz/jrpc v0.3.1 h1:jRxnO5ppOookkL9PuOWw/IloevmzqbsKaGImTR3iALQ=
github.com/go-pkgz/jrpc v0.3.1/go.mod h1:DJg1RfhwvJpVT3YXtk8LxowB7DN5jUoZ3U4MbHnm76M=
github.com/go-pkgz/jrpc v0.4.0 h1:oD7xiGrzDkndkuCjeHGugQXxbggLSV7O1QmHhoc5pYY=
github.com/go-pkgz/jrpc v0.4.0/go.mod h1:JFoY3bRjRyx4M3CbEVDFQStMB1m2gmQ7OjqFK7q3kOo=
github.com/go-pkgz/lcw/v2 v2.0.0 h1:gTwXpiJBhQeA1rXuqkRuLcV79uATFna8CckH8ZBBrH0=
github.com/go-pkgz/lcw/v2 v2.0.0/go.mod h1:yxJHOn+IbQBQHxUqkCtMrbGjIfdYcsBAZcVCBaL1Va8=
github.com/go-pkgz/lgr v0.12.0 h1:uoSCLdiMocZDa+L66DavHG5UIkOJvWKOVqt6sNQllw0=
github.com/go-pkgz/lgr v0.12.0/go.mod h1:A4AxjOthFVFK6jRnVYMeusno5SeDAxcLVHd0kI/lN/Y=
github.com/go-pkgz/lgr v0.12.1 h1:8GVfG2rSARq3Eaj5PP158rtBR2LHVGkwioIkQBGbvKg=
github.com/go-pkgz/lgr v0.12.1/go.mod h1:A4AxjOthFVFK6jRnVYMeusno5SeDAxcLVHd0kI/lN/Y=
github.com/go-pkgz/notify v1.2.0 h1:jqbsbWkodCDB9ffyI9fCG1bTSgidWJRS5UWD/twjU44=
github.com/go-pkgz/notify v1.2.0/go.mod h1:BTHj9ly7xZpaxg91lBdxCxSmkpVQ9R6q5QviX/upeYo=
github.com/go-pkgz/repeater v1.2.0 h1:oJFvjyKdTDd5RCzpzxlzYIZFFj6Zfl17rE1aUfu6UjQ=
github.com/go-pkgz/repeater v1.2.0/go.mod h1:vypP6xamA53MFmafnGUucqOmALKk36xgKu2hSG73LHM=
github.com/go-pkgz/rest v1.20.3 h1:oGGfM8XTnvwek29q1OAhcI1nkKKOpurRFApBiYH44Fk=
github.com/go-pkgz/rest v1.20.3/go.mod h1:NC2xNN/y1rIs0PY13FowKoH8rk9RhJNJ0tTbkBg8Yks=
github.com/go-pkgz/rest v1.20.4 h1:8ufcP1IqoDhCvIFdXPtvyX4HSS16SM6THBe2a6L0/kg=
github.com/go-pkgz/rest v1.20.4/go.mod h1:2/LEZGndSxpVvExsMn48AjUgiTn6kILqjpoaRnl62JU=
github.com/go-pkgz/routegroup v1.6.0 h1:44XHZgF6JIIldRlv+zjg6SygULASmjifnfIQjwCT0e4=
github.com/go-pkgz/routegroup v1.6.0/go.mod h1:Pmu04fhgWhRtBMIJ8HXppnnzOPjnL/IEPBIdO2zmeqg=
github.com/go-pkgz/syncs v1.3.2 h1:gmioASlJNy3gNosPlgvWOM2QP0Hdjzn2u+/sUShgd8E=
github.com/go-pkgz/syncs v1.3.2/go.mod h1:qjgzpp7OpuhDf7BWsW/FHCu9DLjE32NPy6/vXAXT/Cw=
github.com/go-session/session/v3 v3.2.1/go.mod h1:RftEBbyuzqkNCAxIrCLJe+rfBqB/4G11qxq9KYKrx4M=
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
@@ -192,8 +190,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tidwall/btree v0.0.0-20191029221954-400434d76274/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8=
github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI=
github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY=
@@ -249,8 +247,8 @@ github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZ
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M=
github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw=
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ=
go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -264,8 +262,8 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
golang.org/x/image v0.33.0 h1:LXRZRnv1+zGd5XBUVRFmYEphyyKJjQjCRiOuAP3sZfQ=
golang.org/x/image v0.33.0/go.mod h1:DD3OsTYT9chzuzTQt+zMcOlBHgfoKQb1gry8p76Y1sc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+3
View File
@@ -24,6 +24,7 @@ Syntax-wise, it is as close as possible to jQuery, with the same function names
Required Go version:
* Starting with version `v1.11.0` of goquery, Go 1.24+ is required due to its dependencies.
* Starting with version `v1.10.0` of goquery, Go 1.23+ is required due to the use of function-based iterators.
* For `v1.9.0` of goquery, Go 1.18+ is required due to the use of generics.
* For previous goquery versions, a Go version of 1.1+ was required because of the `net/html` dependency.
@@ -46,6 +47,8 @@ Ongoing goquery development is tested on the latest 2 versions of Go.
**Note that goquery's API is now stable, and will not break.**
* **2025-11-16 (v1.11.0)** : Update `go.mod` dependencies, add go1.25 to the test matrix, **goquery now requires Go version 1.24+**.
* **2025-04-11 (v1.10.3)** : Update `go.mod` dependencies, small optimization (thanks [@myxzlpltk](https://github.com/myxzlpltk)).
* **2025-02-13 (v1.10.2)** : Update `go.mod` dependencies, add go1.24 to the test matrix.
* **2024-12-26 (v1.10.1)** : Update `go.mod` dependencies.
* **2024-09-06 (v1.10.0)** : Add `EachIter` which provides an iterator that can be used in `for..range` loops on the `*Selection` object. **goquery now requires Go version 1.23+** (thanks [@amikai](https://github.com/amikai)).
+10 -10
View File
@@ -1,7 +1,6 @@
package goquery
import (
"bytes"
"regexp"
"strings"
@@ -60,14 +59,14 @@ func (s *Selection) SetAttr(attrName, val string) *Selection {
// Text gets the combined text contents of each element in the set of matched
// elements, including their descendants.
func (s *Selection) Text() string {
var buf bytes.Buffer
var builder strings.Builder
// Slightly optimized vs calling Each: no single selection object created
var f func(*html.Node)
f = func(n *html.Node) {
if n.Type == html.TextNode {
// Keep newlines and spaces, like jQuery
buf.WriteString(n.Data)
builder.WriteString(n.Data)
}
if n.FirstChild != nil {
for c := n.FirstChild; c != nil; c = c.NextSibling {
@@ -79,7 +78,7 @@ func (s *Selection) Text() string {
f(n)
}
return buf.String()
return builder.String()
}
// Size is an alias for Length.
@@ -97,16 +96,16 @@ func (s *Selection) Length() int {
func (s *Selection) Html() (ret string, e error) {
// Since there is no .innerHtml, the HTML content must be re-created from
// the nodes using html.Render.
var buf bytes.Buffer
var builder strings.Builder
if len(s.Nodes) > 0 {
for c := s.Nodes[0].FirstChild; c != nil; c = c.NextSibling {
e = html.Render(&buf, c)
e = html.Render(&builder, c)
if e != nil {
return
}
}
ret = buf.String()
ret = builder.String()
}
return
@@ -168,7 +167,7 @@ func (s *Selection) RemoveClass(class ...string) *Selection {
} else {
classes, attr := getClassesAndAttr(n, true)
for _, rcl := range rclasses {
classes = strings.Replace(classes, " "+rcl+" ", " ", -1)
classes = strings.ReplaceAll(classes, " "+rcl+" ", " ")
}
setClasses(n, attr, classes)
@@ -192,8 +191,9 @@ func (s *Selection) ToggleClass(class ...string) *Selection {
for _, n := range s.Nodes {
classes, attr := getClassesAndAttr(n, true)
for _, tcl := range tcls {
if strings.Contains(classes, " "+tcl+" ") {
classes = strings.Replace(classes, " "+tcl+" ", " ", -1)
spaceAroundTcl := " " + tcl + " "
if strings.Contains(classes, spaceAroundTcl) {
classes = strings.ReplaceAll(classes, spaceAroundTcl, " ")
} else {
classes += tcl + " "
}
+10 -11
View File
@@ -1,8 +1,8 @@
package goquery
import (
"bytes"
"io"
"strings"
"golang.org/x/net/html"
)
@@ -26,13 +26,12 @@ var nodeNames = []string{
// Go's net/html package defines the following node types, listed with
// the corresponding returned value from this function:
//
// ErrorNode : #error
// TextNode : #text
// DocumentNode : #document
// ElementNode : the element's tag name
// CommentNode : #comment
// DoctypeNode : the name of the document type
//
// ErrorNode : #error
// TextNode : #text
// DocumentNode : #document
// ElementNode : the element's tag name
// CommentNode : #comment
// DoctypeNode : the name of the document type
func NodeName(s *Selection) string {
if s.Length() == 0 {
return ""
@@ -77,11 +76,11 @@ func Render(w io.Writer, s *Selection) error {
// because this is not a jQuery method (in javascript-land, this is
// a property provided by the DOM).
func OuterHtml(s *Selection) (string, error) {
var buf bytes.Buffer
if err := Render(&buf, s); err != nil {
var builder strings.Builder
if err := Render(&builder, s); err != nil {
return "", err
}
return buf.String(), nil
return builder.String(), nil
}
// Loop through all container nodes to search for the target node.
-25
View File
@@ -1,25 +0,0 @@
## Copyright 2014 Alvaro J. Genial. All rights reserved.
## Use of this source code is governed by a BSD-style
## license that can be found in the LICENSE file.
language: go
go:
- tip
- 1.6
- 1.5
- 1.4
- 1.3
# 1.2
before_install:
# - go get -v golang.org/x/tools/cmd/cover
# - go get -v golang.org/x/tools/cmd/vet
# - go get -v golang.org/x/lint/golint
- export PATH=$PATH:/home/travis/gopath/bin
script:
- go build -v ./...
- go test -v -cover ./...
- go vet ./...
# - golint .
-27
View File
@@ -1,27 +0,0 @@
Copyright (c) 2014 Alvaro J. Genial. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-247
View File
@@ -1,247 +0,0 @@
form
====
A Form Encoding & Decoding Package for Go, written by [Alvaro J. Genial](http://alva.ro).
[![Build Status](https://travis-ci.org/ajg/form.png?branch=master)](https://travis-ci.org/ajg/form)
[![GoDoc](https://godoc.org/github.com/ajg/form?status.png)](https://godoc.org/github.com/ajg/form)
Synopsis
--------
This library is designed to allow seamless, high-fidelity encoding and decoding of arbitrary data in `application/x-www-form-urlencoded` format and as [`url.Values`](http://golang.org/pkg/net/url/#Values). It is intended to be useful primarily in dealing with web forms and URI query strings, both of which natively employ said format.
Unsurprisingly, `form` is modeled after other Go [`encoding`](http://golang.org/pkg/encoding/) packages, in particular [`encoding/json`](http://golang.org/pkg/encoding/json/), and follows the same conventions (see below for more.) It aims to automatically handle any kind of concrete Go [data value](#values) (i.e., not functions, channels, etc.) while providing mechanisms for custom behavior.
Status
------
The implementation is in usable shape and is fairly well tested with its accompanying test suite. The API is unlikely to change much, but still may. Lastly, the code has not yet undergone a security review to ensure it is free of vulnerabilities. Please file an issue or send a pull request for fixes & improvements.
Dependencies
------------
The only requirement is [Go 1.2](http://golang.org/doc/go1.2) or later.
Usage
-----
```go
import "github.com/ajg/form"
// or: "gopkg.in/ajg/form.v1"
```
Given a type like the following...
```go
type User struct {
Name string `form:"name"`
Email string `form:"email"`
Joined time.Time `form:"joined,omitempty"`
Posts []int `form:"posts"`
Preferences map[string]string `form:"prefs"`
Avatar []byte `form:"avatar"`
PasswordHash int64 `form:"-"`
}
```
...it is easy to encode data of that type...
```go
func PostUser(url string, u User) error {
var c http.Client
_, err := c.PostForm(url, form.EncodeToValues(u))
return err
}
```
...as well as decode it...
```go
func Handler(w http.ResponseWriter, r *http.Request) {
var u User
d := form.NewDecoder(r.Body)
if err := d.Decode(&u); err != nil {
http.Error(w, "Form could not be decoded", http.StatusBadRequest)
return
}
fmt.Fprintf(w, "Decoded: %#v", u)
}
```
...without having to do any grunt work.
Field Tags
----------
Like other encoding packages, `form` supports the following options for fields:
- `` `form:"-"` ``: Causes the field to be ignored during encoding and decoding.
- `` `form:"<name>"` ``: Overrides the field's name; useful especially when dealing with external identifiers in camelCase, as are commonly found on the web.
- `` `form:",omitempty"` ``: Elides the field during encoding if it is empty (typically meaning equal to the type's zero value.)
- `` `form:"<name>,omitempty"` ``: The way to combine the two options above.
Values
------
### Simple Values
Values of the following types are all considered simple:
- `bool`
- `int`, `int8`, `int16`, `int32`, `int64`, `rune`
- `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `byte`
- `float32`, `float64`
- `complex64`, `complex128`
- `string`
- `[]byte` (see note)
- [`time.Time`](http://golang.org/pkg/time/#Time)
- [`url.URL`](http://golang.org/pkg/net/url/#URL)
- An alias of any of the above
- A pointer to any of the above
### Composite Values
A composite value is one that can contain other values. Values of the following kinds...
- Maps
- Slices; except `[]byte` (see note)
- Structs; except [`time.Time`](http://golang.org/pkg/time/#Time) and [`url.URL`](http://golang.org/pkg/net/url/#URL)
- Arrays
- An alias of any of the above
- A pointer to any of the above
...are considered composites in general, unless they implement custom marshaling/unmarshaling. Composite values are encoded as a flat mapping of paths to values, where the paths are constructed by joining the parent and child paths with a period (`.`).
(Note: a byte slice is treated as a `string` by default because it's more efficient, but can also be decoded as a slice—i.e., with indexes.)
### Untyped Values
While encouraged, it is not necessary to define a type (e.g. a `struct`) in order to use `form`, since it is able to encode and decode untyped data generically using the following rules:
- Simple values will be treated as a `string`.
- Composite values will be treated as a `map[string]interface{}`, itself able to contain nested values (both scalar and compound) ad infinitum.
- However, if there is a value (of any supported type) already present in a map for a given key, then it will be used when possible, rather than being replaced with a generic value as specified above; this makes it possible to handle partially typed, dynamic or schema-less values.
### Zero Values
By default, and without custom marshaling, zero values (also known as empty/default values) are encoded as the empty string. To disable this behavior, meaning to keep zero values in their literal form (e.g. `0` for integral types), `Encoder` offers a `KeepZeros` setter method, which will do just that when set to `true`.
### Unsupported Values
Values of the following kinds aren't supported and, if present, must be ignored.
- Channel
- Function
- Unsafe pointer
- An alias of any of the above
- A pointer to any of the above
Custom Marshaling
-----------------
There is a default (generally lossless) marshaling & unmarshaling scheme for any concrete data value in Go, which is good enough in most cases. However, it is possible to override it and use a custom scheme. For instance, a "binary" field could be marshaled more efficiently using [base64](http://golang.org/pkg/encoding/base64/) to prevent it from being percent-escaped during serialization to `application/x-www-form-urlencoded` format.
Because `form` provides support for [`encoding.TextMarshaler`](http://golang.org/pkg/encoding/#TextMarshaler) and [`encoding.TextUnmarshaler`](http://golang.org/pkg/encoding/#TextUnmarshaler) it is easy to do that; for instance, like this:
```go
import "encoding"
type Binary []byte
var (
_ encoding.TextMarshaler = &Binary{}
_ encoding.TextUnmarshaler = &Binary{}
)
func (b Binary) MarshalText() ([]byte, error) {
return []byte(base64.URLEncoding.EncodeToString([]byte(b))), nil
}
func (b *Binary) UnmarshalText(text []byte) error {
bs, err := base64.URLEncoding.DecodeString(string(text))
if err == nil {
*b = Binary(bs)
}
return err
}
```
Now any value with type `Binary` will automatically be encoded using the [URL](http://golang.org/pkg/encoding/base64/#URLEncoding) variant of base64. It is left as an exercise to the reader to improve upon this scheme by eliminating the need for padding (which, besides being superfluous, uses `=`, a character that will end up percent-escaped.)
Keys
----
In theory any value can be a key as long as it has a string representation. However, by default, periods have special meaning to `form`, and thus, under the hood (i.e. in encoded form) they are transparently escaped using a preceding backslash (`\`). Backslashes within keys, themselves, are also escaped in this manner (e.g. as `\\`) in order to permit representing `\.` itself (as `\\\.`).
(Note: it is normally unnecessary to deal with this issue unless keys are being constructed manually—e.g. literally embedded in HTML or in a URI.)
The default delimiter and escape characters used for encoding and decoding composite keys can be changed using the `DelimitWith` and `EscapeWith` setter methods of `Encoder` and `Decoder`, respectively. For example...
```go
package main
import (
"os"
"github.com/ajg/form"
)
func main() {
type B struct {
Qux string `form:"qux"`
}
type A struct {
FooBar B `form:"foo.bar"`
}
a := A{FooBar: B{"XYZ"}}
os.Stdout.WriteString("Default: ")
form.NewEncoder(os.Stdout).Encode(a)
os.Stdout.WriteString("\nCustom: ")
form.NewEncoder(os.Stdout).DelimitWith('/').Encode(a)
os.Stdout.WriteString("\n")
}
```
...will produce...
```
Default: foo%5C.bar.qux=XYZ
Custom: foo.bar%2Fqux=XYZ
```
(`%5C` and `%2F` represent `\` and `/`, respectively.)
Limitations
-----------
- Circular (self-referential) values are untested.
Future Work
-----------
The following items would be nice to have in the future—though they are not being worked on yet:
- An option to treat all values as if they had been tagged with `omitempty`.
- An option to automatically treat all field names in `camelCase` or `underscore_case`.
- Built-in support for the types in [`math/big`](http://golang.org/pkg/math/big/).
- Built-in support for the types in [`image/color`](http://golang.org/pkg/image/color/).
- Improve encoding/decoding by reading/writing directly from/to the `io.Reader`/`io.Writer` when possible, rather than going through an intermediate representation (i.e. `node`) which requires more memory.
(Feel free to implement any of these and then send a pull request.)
Related Work
------------
- Package [gorilla/schema](https://github.com/gorilla/schema), which only implements decoding.
- Package [google/go-querystring](https://github.com/google/go-querystring), which only implements encoding.
License
-------
This library is distributed under a BSD-style [LICENSE](./LICENSE).
-4
View File
@@ -1,4 +0,0 @@
TODO
====
- Document IgnoreCase and IgnoreUnknownKeys in README.
-370
View File
@@ -1,370 +0,0 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"fmt"
"io"
"io/ioutil"
"net/url"
"reflect"
"strconv"
"time"
)
// NewDecoder returns a new form Decoder.
func NewDecoder(r io.Reader) *Decoder {
return &Decoder{r, defaultDelimiter, defaultEscape, false, false}
}
// Decoder decodes data from a form (application/x-www-form-urlencoded).
type Decoder struct {
r io.Reader
d rune
e rune
ignoreUnknown bool
ignoreCase bool
}
// DelimitWith sets r as the delimiter used for composite keys by Decoder d and returns the latter; it is '.' by default.
func (d *Decoder) DelimitWith(r rune) *Decoder {
d.d = r
return d
}
// EscapeWith sets r as the escape used for delimiters (and to escape itself) by Decoder d and returns the latter; it is '\\' by default.
func (d *Decoder) EscapeWith(r rune) *Decoder {
d.e = r
return d
}
// Decode reads in and decodes form-encoded data into dst.
func (d Decoder) Decode(dst interface{}) error {
bs, err := ioutil.ReadAll(d.r)
if err != nil {
return err
}
vs, err := url.ParseQuery(string(bs))
if err != nil {
return err
}
v := reflect.ValueOf(dst)
return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
}
// IgnoreUnknownKeys if set to true it will make the Decoder ignore values
// that are not found in the destination object instead of returning an error.
func (d *Decoder) IgnoreUnknownKeys(ignoreUnknown bool) {
d.ignoreUnknown = ignoreUnknown
}
// IgnoreCase if set to true it will make the Decoder try to set values in the
// destination object even if the case does not match.
func (d *Decoder) IgnoreCase(ignoreCase bool) {
d.ignoreCase = ignoreCase
}
// DecodeString decodes src into dst.
func (d Decoder) DecodeString(dst interface{}, src string) error {
vs, err := url.ParseQuery(src)
if err != nil {
return err
}
v := reflect.ValueOf(dst)
return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
}
// DecodeValues decodes vs into dst.
func (d Decoder) DecodeValues(dst interface{}, vs url.Values) error {
v := reflect.ValueOf(dst)
return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v)))
}
// DecodeString decodes src into dst.
func DecodeString(dst interface{}, src string) error {
return NewDecoder(nil).DecodeString(dst, src)
}
// DecodeValues decodes vs into dst.
func DecodeValues(dst interface{}, vs url.Values) error {
return NewDecoder(nil).DecodeValues(dst, vs)
}
func (d Decoder) decodeNode(v reflect.Value, n node) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
if v.Kind() == reflect.Slice {
return fmt.Errorf("could not decode directly into slice; use pointer to slice")
}
d.decodeValue(v, n)
return nil
}
func (d Decoder) decodeValue(v reflect.Value, x interface{}) {
t := v.Type()
k := v.Kind()
if k == reflect.Ptr && v.IsNil() {
v.Set(reflect.New(t.Elem()))
}
if unmarshalValue(v, x) {
return
}
empty := isEmpty(x)
switch k {
case reflect.Ptr:
d.decodeValue(v.Elem(), x)
return
case reflect.Interface:
if !v.IsNil() {
d.decodeValue(v.Elem(), x)
return
} else if empty {
return // Allow nil interfaces only if empty.
} else {
panic("form: cannot decode non-empty value into into nil interface")
}
}
if empty {
v.Set(reflect.Zero(t)) // Treat the empty string as the zero value.
return
}
switch k {
case reflect.Struct:
if t.ConvertibleTo(timeType) {
d.decodeTime(v, x)
} else if t.ConvertibleTo(urlType) {
d.decodeURL(v, x)
} else {
d.decodeStruct(v, x)
}
case reflect.Slice:
d.decodeSlice(v, x)
case reflect.Array:
d.decodeArray(v, x)
case reflect.Map:
d.decodeMap(v, x)
case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func:
panic(t.String() + " has unsupported kind " + k.String())
default:
d.decodeBasic(v, x)
}
}
func (d Decoder) decodeStruct(v reflect.Value, x interface{}) {
t := v.Type()
for k, c := range getNode(x) {
if f, ok := findField(v, k, d.ignoreCase); !ok && k == "" {
panic(getString(x) + " cannot be decoded as " + t.String())
} else if !ok {
if !d.ignoreUnknown {
panic(k + " doesn't exist in " + t.String())
}
} else if !f.CanSet() {
panic(k + " cannot be set in " + t.String())
} else {
d.decodeValue(f, c)
}
}
}
func (d Decoder) decodeMap(v reflect.Value, x interface{}) {
t := v.Type()
if v.IsNil() {
v.Set(reflect.MakeMap(t))
}
for k, c := range getNode(x) {
i := reflect.New(t.Key()).Elem()
d.decodeValue(i, k)
w := v.MapIndex(i)
if w.IsValid() { // We have an actual element value to decode into.
if w.Kind() == reflect.Interface {
w = w.Elem()
}
w = reflect.New(w.Type()).Elem()
} else if t.Elem().Kind() != reflect.Interface { // The map's element type is concrete.
w = reflect.New(t.Elem()).Elem()
} else {
// The best we can do here is to decode as either a string (for scalars) or a map[string]interface {} (for the rest).
// We could try to guess the type based on the string (e.g. true/false => bool) but that'll get ugly fast,
// especially if we have to guess the kind (slice vs. array vs. map) and index type (e.g. string, int, etc.)
switch c.(type) {
case node:
w = reflect.MakeMap(stringMapType)
case string:
w = reflect.New(stringType).Elem()
default:
panic("value is neither node nor string")
}
}
d.decodeValue(w, c)
v.SetMapIndex(i, w)
}
}
func (d Decoder) decodeArray(v reflect.Value, x interface{}) {
t := v.Type()
for k, c := range getNode(x) {
i, err := strconv.Atoi(k)
if err != nil {
panic(k + " is not a valid index for type " + t.String())
}
if l := v.Len(); i >= l {
panic("index is above array size")
}
d.decodeValue(v.Index(i), c)
}
}
func (d Decoder) decodeSlice(v reflect.Value, x interface{}) {
t := v.Type()
if t.Elem().Kind() == reflect.Uint8 {
// Allow, but don't require, byte slices to be encoded as a single string.
if s, ok := x.(string); ok {
v.SetBytes([]byte(s))
return
}
}
// NOTE: Implicit indexing is currently done at the parseValues level,
// so if if an implicitKey reaches here it will always replace the last.
implicit := 0
for k, c := range getNode(x) {
var i int
if k == implicitKey {
i = implicit
implicit++
} else {
explicit, err := strconv.Atoi(k)
if err != nil {
panic(k + " is not a valid index for type " + t.String())
}
i = explicit
implicit = explicit + 1
}
// "Extend" the slice if it's too short.
if l := v.Len(); i >= l {
delta := i - l + 1
v.Set(reflect.AppendSlice(v, reflect.MakeSlice(t, delta, delta)))
}
d.decodeValue(v.Index(i), c)
}
}
func (d Decoder) decodeBasic(v reflect.Value, x interface{}) {
t := v.Type()
switch k, s := t.Kind(), getString(x); k {
case reflect.Bool:
if b, e := strconv.ParseBool(s); e == nil {
v.SetBool(b)
} else {
panic("could not parse bool from " + strconv.Quote(s))
}
case reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
if i, e := strconv.ParseInt(s, 10, 64); e == nil {
v.SetInt(i)
} else {
panic("could not parse int from " + strconv.Quote(s))
}
case reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64:
if u, e := strconv.ParseUint(s, 10, 64); e == nil {
v.SetUint(u)
} else {
panic("could not parse uint from " + strconv.Quote(s))
}
case reflect.Float32,
reflect.Float64:
if f, e := strconv.ParseFloat(s, 64); e == nil {
v.SetFloat(f)
} else {
panic("could not parse float from " + strconv.Quote(s))
}
case reflect.Complex64,
reflect.Complex128:
var c complex128
if n, err := fmt.Sscanf(s, "%g", &c); n == 1 && err == nil {
v.SetComplex(c)
} else {
panic("could not parse complex from " + strconv.Quote(s))
}
case reflect.String:
v.SetString(s)
default:
panic(t.String() + " has unsupported kind " + k.String())
}
}
func (d Decoder) decodeTime(v reflect.Value, x interface{}) {
t := v.Type()
s := getString(x)
// TODO: Find a more efficient way to do this.
for _, f := range allowedTimeFormats {
if p, err := time.Parse(f, s); err == nil {
v.Set(reflect.ValueOf(p).Convert(v.Type()))
return
}
}
panic("cannot decode string `" + s + "` as " + t.String())
}
func (d Decoder) decodeURL(v reflect.Value, x interface{}) {
t := v.Type()
s := getString(x)
if u, err := url.Parse(s); err == nil {
v.Set(reflect.ValueOf(*u).Convert(v.Type()))
return
}
panic("cannot decode string `" + s + "` as " + t.String())
}
var allowedTimeFormats = []string{
"2006-01-02T15:04:05.999999999Z07:00",
"2006-01-02T15:04:05.999999999Z07",
"2006-01-02T15:04:05.999999999Z",
"2006-01-02T15:04:05.999999999",
"2006-01-02T15:04:05Z07:00",
"2006-01-02T15:04:05Z07",
"2006-01-02T15:04:05Z",
"2006-01-02T15:04:05",
"2006-01-02T15:04Z",
"2006-01-02T15:04",
"2006-01-02T15Z",
"2006-01-02T15",
"2006-01-02",
"2006-01",
"2006",
"15:04:05.999999999Z07:00",
"15:04:05.999999999Z07",
"15:04:05.999999999Z",
"15:04:05.999999999",
"15:04:05Z07:00",
"15:04:05Z07",
"15:04:05Z",
"15:04:05",
"15:04Z",
"15:04",
"15Z",
"15",
}
-388
View File
@@ -1,388 +0,0 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"encoding"
"errors"
"fmt"
"io"
"net/url"
"reflect"
"strconv"
"strings"
"time"
)
// NewEncoder returns a new form Encoder.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w, defaultDelimiter, defaultEscape, false}
}
// Encoder provides a way to encode to a Writer.
type Encoder struct {
w io.Writer
d rune
e rune
z bool
}
// DelimitWith sets r as the delimiter used for composite keys by Encoder e and returns the latter; it is '.' by default.
func (e *Encoder) DelimitWith(r rune) *Encoder {
e.d = r
return e
}
// EscapeWith sets r as the escape used for delimiters (and to escape itself) by Encoder e and returns the latter; it is '\\' by default.
func (e *Encoder) EscapeWith(r rune) *Encoder {
e.e = r
return e
}
// KeepZeros sets whether Encoder e should keep zero (default) values in their literal form when encoding, and returns the former; by default zero values are not kept, but are rather encoded as the empty string.
func (e *Encoder) KeepZeros(z bool) *Encoder {
e.z = z
return e
}
// Encode encodes dst as form and writes it out using the Encoder's Writer.
func (e Encoder) Encode(dst interface{}) error {
v := reflect.ValueOf(dst)
n, err := encodeToNode(v, e.z)
if err != nil {
return err
}
s := n.values(e.d, e.e).Encode()
l, err := io.WriteString(e.w, s)
switch {
case err != nil:
return err
case l != len(s):
return errors.New("could not write data completely")
}
return nil
}
// EncodeToString encodes dst as a form and returns it as a string.
func EncodeToString(dst interface{}) (string, error) {
v := reflect.ValueOf(dst)
n, err := encodeToNode(v, false)
if err != nil {
return "", err
}
vs := n.values(defaultDelimiter, defaultEscape)
return vs.Encode(), nil
}
// EncodeToValues encodes dst as a form and returns it as Values.
func EncodeToValues(dst interface{}) (url.Values, error) {
v := reflect.ValueOf(dst)
n, err := encodeToNode(v, false)
if err != nil {
return nil, err
}
vs := n.values(defaultDelimiter, defaultEscape)
return vs, nil
}
func encodeToNode(v reflect.Value, z bool) (n node, err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("%v", e)
}
}()
return getNode(encodeValue(v, z)), nil
}
func encodeValue(v reflect.Value, z bool) interface{} {
t := v.Type()
k := v.Kind()
if s, ok := marshalValue(v); ok {
return s
} else if !z && isEmptyValue(v) {
return "" // Treat the zero value as the empty string.
}
switch k {
case reflect.Ptr, reflect.Interface:
return encodeValue(v.Elem(), z)
case reflect.Struct:
if t.ConvertibleTo(timeType) {
return encodeTime(v)
} else if t.ConvertibleTo(urlType) {
return encodeURL(v)
}
return encodeStruct(v, z)
case reflect.Slice:
return encodeSlice(v, z)
case reflect.Array:
return encodeArray(v, z)
case reflect.Map:
return encodeMap(v, z)
case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func:
panic(t.String() + " has unsupported kind " + t.Kind().String())
default:
return encodeBasic(v)
}
}
func encodeStruct(v reflect.Value, z bool) interface{} {
t := v.Type()
n := node{}
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
k, oe := fieldInfo(f)
if k == "-" {
continue
} else if fv := v.Field(i); oe && isEmptyValue(fv) {
delete(n, k)
} else {
n[k] = encodeValue(fv, z)
}
}
return n
}
func encodeMap(v reflect.Value, z bool) interface{} {
n := node{}
for _, i := range v.MapKeys() {
k := getString(encodeValue(i, z))
n[k] = encodeValue(v.MapIndex(i), z)
}
return n
}
func encodeArray(v reflect.Value, z bool) interface{} {
n := node{}
for i := 0; i < v.Len(); i++ {
n[strconv.Itoa(i)] = encodeValue(v.Index(i), z)
}
return n
}
func encodeSlice(v reflect.Value, z bool) interface{} {
t := v.Type()
if t.Elem().Kind() == reflect.Uint8 {
return string(v.Bytes()) // Encode byte slices as a single string by default.
}
n := node{}
for i := 0; i < v.Len(); i++ {
n[strconv.Itoa(i)] = encodeValue(v.Index(i), z)
}
return n
}
func encodeTime(v reflect.Value) string {
t := v.Convert(timeType).Interface().(time.Time)
if t.Year() == 0 && (t.Month() == 0 || t.Month() == 1) && (t.Day() == 0 || t.Day() == 1) {
return t.Format("15:04:05.999999999Z07:00")
} else if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 && t.Nanosecond() == 0 {
return t.Format("2006-01-02")
}
return t.Format("2006-01-02T15:04:05.999999999Z07:00")
}
func encodeURL(v reflect.Value) string {
u := v.Convert(urlType).Interface().(url.URL)
return u.String()
}
func encodeBasic(v reflect.Value) string {
t := v.Type()
switch k := t.Kind(); k {
case reflect.Bool:
return strconv.FormatBool(v.Bool())
case reflect.Int,
reflect.Int8,
reflect.Int16,
reflect.Int32,
reflect.Int64:
return strconv.FormatInt(v.Int(), 10)
case reflect.Uint,
reflect.Uint8,
reflect.Uint16,
reflect.Uint32,
reflect.Uint64:
return strconv.FormatUint(v.Uint(), 10)
case reflect.Float32:
return strconv.FormatFloat(v.Float(), 'g', -1, 32)
case reflect.Float64:
return strconv.FormatFloat(v.Float(), 'g', -1, 64)
case reflect.Complex64, reflect.Complex128:
s := fmt.Sprintf("%g", v.Complex())
return strings.TrimSuffix(strings.TrimPrefix(s, "("), ")")
case reflect.String:
return v.String()
}
panic(t.String() + " has unsupported kind " + t.Kind().String())
}
func isEmptyValue(v reflect.Value) bool {
switch t := v.Type(); v.Kind() {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return v.Float() == 0
case reflect.Complex64, reflect.Complex128:
return v.Complex() == 0
case reflect.Interface, reflect.Ptr:
return v.IsNil()
case reflect.Struct:
if t.ConvertibleTo(timeType) {
return v.Convert(timeType).Interface().(time.Time).IsZero()
}
return reflect.DeepEqual(v, reflect.Zero(t))
}
return false
}
// canIndexOrdinally returns whether a value contains an ordered sequence of elements.
func canIndexOrdinally(v reflect.Value) bool {
if !v.IsValid() {
return false
}
switch t := v.Type(); t.Kind() {
case reflect.Ptr, reflect.Interface:
return canIndexOrdinally(v.Elem())
case reflect.Slice, reflect.Array:
return true
}
return false
}
func fieldInfo(f reflect.StructField) (k string, oe bool) {
if f.PkgPath != "" { // Skip private fields.
return omittedKey, oe
}
k = f.Name
tag := f.Tag.Get("form")
if tag == "" {
return k, oe
}
ps := strings.SplitN(tag, ",", 2)
if ps[0] != "" {
k = ps[0]
}
if len(ps) == 2 {
oe = ps[1] == "omitempty"
}
return k, oe
}
func findField(v reflect.Value, n string, ignoreCase bool) (reflect.Value, bool) {
t := v.Type()
l := v.NumField()
var lowerN string
caseInsensitiveMatch := -1
if ignoreCase {
lowerN = strings.ToLower(n)
}
// First try named fields.
for i := 0; i < l; i++ {
f := t.Field(i)
k, _ := fieldInfo(f)
if k == omittedKey {
continue
} else if n == k {
return v.Field(i), true
} else if ignoreCase && lowerN == strings.ToLower(k) {
caseInsensitiveMatch = i
}
}
// If no exact match was found try case insensitive match.
if caseInsensitiveMatch != -1 {
return v.Field(caseInsensitiveMatch), true
}
// Then try anonymous (embedded) fields.
for i := 0; i < l; i++ {
f := t.Field(i)
k, _ := fieldInfo(f)
if k == omittedKey || !f.Anonymous { // || k != "" ?
continue
}
fv := v.Field(i)
fk := fv.Kind()
for fk == reflect.Ptr || fk == reflect.Interface {
fv = fv.Elem()
fk = fv.Kind()
}
if fk != reflect.Struct {
continue
}
if ev, ok := findField(fv, n, ignoreCase); ok {
return ev, true
}
}
return reflect.Value{}, false
}
var (
stringType = reflect.TypeOf(string(""))
stringMapType = reflect.TypeOf(map[string]interface{}{})
timeType = reflect.TypeOf(time.Time{})
timePtrType = reflect.TypeOf(&time.Time{})
urlType = reflect.TypeOf(url.URL{})
)
func skipTextMarshalling(t reflect.Type) bool {
/*// Skip time.Time because its text unmarshaling is overly rigid:
return t == timeType || t == timePtrType*/
// Skip time.Time & convertibles because its text unmarshaling is overly rigid:
return t.ConvertibleTo(timeType) || t.ConvertibleTo(timePtrType)
}
func unmarshalValue(v reflect.Value, x interface{}) bool {
if skipTextMarshalling(v.Type()) {
return false
}
tu, ok := v.Interface().(encoding.TextUnmarshaler)
if !ok && !v.CanAddr() {
return false
} else if !ok {
return unmarshalValue(v.Addr(), x)
}
s := getString(x)
if err := tu.UnmarshalText([]byte(s)); err != nil {
panic(err)
}
return true
}
func marshalValue(v reflect.Value) (string, bool) {
if skipTextMarshalling(v.Type()) {
return "", false
}
tm, ok := v.Interface().(encoding.TextMarshaler)
if !ok && !v.CanAddr() {
return "", false
} else if !ok {
return marshalValue(v.Addr())
}
bs, err := tm.MarshalText()
if err != nil {
panic(err)
}
return string(bs), true
}
-14
View File
@@ -1,14 +0,0 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package form implements encoding and decoding of application/x-www-form-urlencoded data.
package form
const (
implicitKey = "_"
omittedKey = "-"
defaultDelimiter = '.'
defaultEscape = '\\'
)
-152
View File
@@ -1,152 +0,0 @@
// Copyright 2014 Alvaro J. Genial. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package form
import (
"net/url"
"strconv"
"strings"
)
type node map[string]interface{}
func (n node) values(d, e rune) url.Values {
vs := url.Values{}
n.merge(d, e, "", &vs)
return vs
}
func (n node) merge(d, e rune, p string, vs *url.Values) {
for k, x := range n {
switch y := x.(type) {
case string:
vs.Add(p+escape(d, e, k), y)
case node:
y.merge(d, e, p+escape(d, e, k)+string(d), vs)
default:
panic("value is neither string nor node")
}
}
}
// TODO: Add tests for implicit indexing.
func parseValues(d, e rune, vs url.Values, canIndexFirstLevelOrdinally bool) node {
// NOTE: Because of the flattening of potentially multiple strings to one key, implicit indexing works:
// i. At the first level; e.g. Foo.Bar=A&Foo.Bar=B becomes 0.Foo.Bar=A&1.Foo.Bar=B
// ii. At the last level; e.g. Foo.Bar._=A&Foo.Bar._=B becomes Foo.Bar.0=A&Foo.Bar.1=B
// TODO: At in-between levels; e.g. Foo._.Bar=A&Foo._.Bar=B becomes Foo.0.Bar=A&Foo.1.Bar=B
// (This last one requires that there only be one placeholder in order for it to be unambiguous.)
m := map[string]string{}
for k, ss := range vs {
indexLastLevelOrdinally := strings.HasSuffix(k, string(d)+implicitKey)
for i, s := range ss {
if canIndexFirstLevelOrdinally {
k = strconv.Itoa(i) + string(d) + k
} else if indexLastLevelOrdinally {
k = strings.TrimSuffix(k, implicitKey) + strconv.Itoa(i)
}
m[k] = s
}
}
n := node{}
for k, s := range m {
n = n.split(d, e, k, s)
}
return n
}
func splitPath(d, e rune, path string) (k, rest string) {
esc := false
for i, r := range path {
switch {
case !esc && r == e:
esc = true
case !esc && r == d:
return unescape(d, e, path[:i]), path[i+1:]
default:
esc = false
}
}
return unescape(d, e, path), ""
}
func (n node) split(d, e rune, path, s string) node {
k, rest := splitPath(d, e, path)
if rest == "" {
return add(n, k, s)
}
if _, ok := n[k]; !ok {
n[k] = node{}
}
c := getNode(n[k])
n[k] = c.split(d, e, rest, s)
return n
}
func add(n node, k, s string) node {
if n == nil {
return node{k: s}
}
if _, ok := n[k]; ok {
panic("key " + k + " already set")
}
n[k] = s
return n
}
func isEmpty(x interface{}) bool {
switch y := x.(type) {
case string:
return y == ""
case node:
if s, ok := y[""].(string); ok {
return s == ""
}
return false
}
panic("value is neither string nor node")
}
func getNode(x interface{}) node {
switch y := x.(type) {
case string:
return node{"": y}
case node:
return y
}
panic("value is neither string nor node")
}
func getString(x interface{}) string {
switch y := x.(type) {
case string:
return y
case node:
if s, ok := y[""].(string); ok {
return s
}
return ""
}
panic("value is neither string nor node")
}
func escape(d, e rune, s string) string {
s = strings.Replace(s, string(e), string(e)+string(e), -1) // Escape the escape (\ => \\)
s = strings.Replace(s, string(d), string(e)+string(d), -1) // Escape the delimiter (. => \.)
return s
}
func unescape(d, e rune, s string) string {
s = strings.Replace(s, string(e)+string(d), string(d), -1) // Unescape the delimiter (\. => .)
s = strings.Replace(s, string(e)+string(e), string(e), -1) // Unescape the escape (\\ => \)
return s
}
-18
View File
@@ -1,18 +0,0 @@
#!/bin/bash -eu
# TODO: Only colorize messages given a suitable terminal.
# FIXME: Handle case in which no stash entry is created due to no changes.
printf "\e[30m=== PRE-COMMIT STARTING ===\e[m\n"
git stash save --quiet --keep-index --include-untracked
if go build -v ./... && go test -v -cover ./... && go vet ./... && golint . && travis-lint; then
result=$?
printf "\e[32m=== PRE-COMMIT SUCCEEDED ===\e[m\n"
else
result=$?
printf "\e[31m=== PRE-COMMIT FAILED ===\e[m\n"
fi
git stash pop --quiet
exit $result
@@ -23,3 +23,6 @@ _models/
_examples/
*.min.*
build/
cmd/chromad/static/chroma.wasm
cmd/chromad/static/wasm_exec.js
+5 -11
View File
@@ -1,7 +1,5 @@
run:
tests: true
skip-dirs:
- _examples
output:
print-issued-lines: false
@@ -9,8 +7,6 @@ output:
linters:
enable-all: true
disable:
- maligned
- megacheck
- lll
- gocyclo
- dupl
@@ -18,9 +14,7 @@ linters:
- funlen
- godox
- wsl
- gomnd
- gocognit
- goerr113
- nolintlint
- testpackage
- godot
@@ -28,12 +22,10 @@ linters:
- paralleltest
- nlreturn
- cyclop
- exhaustivestruct
- gci
- gofumpt
- errorlint
- exhaustive
- ifshort
- wrapcheck
- stylecheck
- thelper
@@ -46,7 +38,6 @@ linters:
- ireturn
- maintidx
- govet
- nosnakecase
- testableexamples
- musttag
- depguard
@@ -54,10 +45,11 @@ linters:
- perfsprint
- mnd
- predeclared
- recvcheck
- tenv
- err113
linters-settings:
govet:
check-shadowing: true
gocyclo:
min-complexity: 10
dupl:
@@ -72,6 +64,8 @@ linters-settings:
issues:
exclude-dirs:
- _examples
max-per-linter: 0
max-same: 0
exclude-use-default: false
+18 -21
View File
@@ -4,34 +4,31 @@ release:
owner: alecthomas
name: chroma
brews:
-
install: bin.install "chroma"
- install: bin.install "chroma"
env:
- CGO_ENABLED=0
builds:
- goos:
- linux
- darwin
- windows
goarch:
- arm64
- amd64
- "386"
goarm:
- "6"
dir: ./cmd/chroma
main: .
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
binary: chroma
- goos:
- linux
- darwin
- windows
goarch:
- arm64
- amd64
- "386"
goarm:
- "6"
dir: ./cmd/chroma
main: .
ldflags: -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
binary: chroma
archives:
-
format: tar.gz
name_template: '{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{
.Arm }}{{ end }}'
- format: tar.gz
name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}"
files:
- COPYING
- README*
snapshot:
name_template: SNAPSHOT-{{ .Commit }}
checksum:
name_template: '{{ .ProjectName }}-{{ .Version }}-checksums.txt'
name_template: "{{ .ProjectName }}-{{ .Version }}-checksums.txt"
+65
View File
@@ -0,0 +1,65 @@
# Multi-stage Dockerfile for chromad Go application using Hermit-managed tools
# Build stage
FROM ubuntu:24.04 AS builder
# Install system dependencies
RUN apt-get update && apt-get install -y \
curl \
git \
make \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /app
# Copy the entire project (including bin directory with Hermit tools)
COPY . .
# Make Hermit tools executable and add to PATH
ENV PATH="/app/bin:${PATH}"
# Set Go environment variables for static compilation
ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64
# Build the application using make
RUN make build/chromad
# Runtime stage
FROM alpine:3.22 AS runtime
# Install ca-certificates for HTTPS requests
RUN apk --no-cache add ca-certificates curl
# Create a non-root user
RUN addgroup -g 1001 chromad && \
adduser -D -s /bin/sh -u 1001 -G chromad chromad
# Set working directory
WORKDIR /app
# Copy the binary from build stage
COPY --from=builder /app/build/chromad /app/chromad
# Change ownership to non-root user
RUN chown chromad:chromad /app/chromad
# Switch to non-root user
USER chromad
# Expose port (default is 8080, but can be overridden via PORT env var)
EXPOSE 8080
# Set default environment variables
ENV PORT=8080
ENV CHROMA_CSRF_KEY="testtest"
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -fsSL http://127.0.0.1:8080/ > /dev/null
# Run the application
CMD ["sh", "-c", "./chromad --csrf-key=$CHROMA_CSRF_KEY --bind=0.0.0.0:$PORT"]
+24 -5
View File
@@ -6,17 +6,36 @@ export GOARCH ?= amd64
all: README.md tokentype_string.go
README.md: lexers/*/*.go
./table.py
README.md: lexers/*.go lexers/embedded/*.xml
GOOS= GOARCH= ./table.py
tokentype_string.go: types.go
go generate
chromad:
.PHONY: format-js
format-js:
biome format --write cmd/chromad/static/{index.js,chroma.js}
.PHONY: chromad
chromad: build/chromad
build/chromad: $(shell find cmd/chromad -name '*.go' -o -name '*.html' -o -name '*.css' -o -name '*.js') \
cmd/chromad/static/wasm_exec.js \
cmd/chromad/static/chroma.wasm
rm -rf build
esbuild --bundle cmd/chromad/static/index.js --minify --outfile=cmd/chromad/static/index.min.js
esbuild --platform=node --bundle cmd/chromad/static/index.js --minify --outfile=cmd/chromad/static/index.min.js
esbuild --bundle cmd/chromad/static/index.css --minify --outfile=cmd/chromad/static/index.min.css
(export CGOENABLED=0 ; cd ./cmd/chromad && go build -ldflags="-X 'main.version=$(VERSION)'" -o ../../build/chromad .)
(export CGOENABLED=0 ; go build -C cmd/chromad -ldflags="-X 'main.version=$(VERSION)'" -o ../../build/chromad .)
cmd/chromad/static/wasm_exec.js: $(shell tinygo env TINYGOROOT)/targets/wasm_exec.js
install -m644 $< $@
cmd/chromad/static/chroma.wasm: $(shell git ls-files | grep '\.go|\.xml')
if type tinygo > /dev/null; then \
tinygo build -no-debug -target wasm -o $@ cmd/libchromawasm/main.go; \
else \
GOOS=js GOARCH=wasm go build -o $@ cmd/libchromawasm/main.go; \
fi
upload: build/chromad
scp build/chromad root@swapoff.org: && \
+41 -31
View File
@@ -1,6 +1,9 @@
# Chroma — A general purpose syntax highlighter in pure Go
![Chroma](chroma.jpg)
# A general purpose syntax highlighter in pure Go
[![Go Reference](https://pkg.go.dev/badge/github.com/alecthomas/chroma/v2.svg)](https://pkg.go.dev/github.com/alecthomas/chroma/v2) [![CI](https://github.com/alecthomas/chroma/actions/workflows/ci.yml/badge.svg)](https://github.com/alecthomas/chroma/actions/workflows/ci.yml) [![Slack chat](https://img.shields.io/static/v1?logo=slack&style=flat&label=slack&color=green&message=gophers)](https://invite.slack.golangbridge.org/)
[![Golang Documentation](https://godoc.org/github.com/alecthomas/chroma?status.svg)](https://godoc.org/github.com/alecthomas/chroma) [![CI](https://github.com/alecthomas/chroma/actions/workflows/ci.yml/badge.svg)](https://github.com/alecthomas/chroma/actions/workflows/ci.yml) [![Slack chat](https://img.shields.io/static/v1?logo=slack&style=flat&label=slack&color=green&message=gophers)](https://invite.slack.golangbridge.org/)
Chroma takes source code and other structured text and converts it into syntax
highlighted HTML, ANSI-coloured text, etc.
@@ -31,33 +34,34 @@ translators for Pygments lexers and styles.
## Supported languages
| Prefix | Language |
| :----: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Agda, AL, Alloy, Angular2, ANTLR, ApacheConf, APL, AppleScript, ArangoDB AQL, Arduino, ArmAsm, AutoHotkey, AutoIt, Awk |
| B | Ballerina, Bash, Bash Session, Batchfile, BibTeX, Bicep, BlitzBasic, BNF, BQN, Brainfuck |
| C | C, C#, C++, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Chapel, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Crystal, CSS, Cython |
| D | D, Dart, Dax, Desktop Entry, Diff, Django/Jinja, dns, Docker, DTD, Dylan |
| E | EBNF, Elixir, Elm, EmacsLisp, Erlang |
| F | Factor, Fennel, Fish, Forth, Fortran, FortranFixed, FSharp |
| G | GAS, GDScript, Genshi, Genshi HTML, Genshi Text, Gherkin, Gleam, GLSL, Gnuplot, Go, Go HTML Template, Go Text Template, GraphQL, Groff, Groovy |
| H | Handlebars, Hare, Haskell, Haxe, HCL, Hexdump, HLB, HLSL, HolyC, HTML, HTTP, Hy |
| I | Idris, Igor, INI, Io, ISCdhcpd |
| J | J, Java, JavaScript, JSON, Jsonnet, Julia, Jungle |
| K | Kotlin |
| L | Lighttpd configuration file, LLVM, Lua |
| M | Makefile, Mako, markdown, Mason, Materialize SQL dialect, Mathematica, Matlab, MCFunction, Meson, Metal, MiniZinc, MLIR, Modula-2, MonkeyC, MorrowindScript, Myghty, MySQL |
| N | NASM, Natural, Newspeak, Nginx configuration file, Nim, Nix, NSIS |
| O | Objective-C, OCaml, Octave, Odin, OnesEnterprise, OpenEdge ABL, OpenSCAD, Org Mode |
| P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Plutus Core, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerQuery, PowerShell, Prolog, PromQL, Promela, properties, Protocol Buffer, PRQL, PSL, Puppet, Python, Python 2 |
| Q | QBasic, QML |
| R | R, Racket, Ragel, Raku, react, ReasonML, reg, Rego, reStructuredText, Rexx, RPMSpec, Ruby, Rust |
| S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Sed, Sieve, Smali, Smalltalk, Smarty, SNBT, Snobol, Solidity, SourcePawn, SPARQL, SQL, SquidConf, Standard ML, stas, Stylus, Svelte, Swift, SYSTEMD, systemverilog |
| T | TableGen, Tal, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData, Typst |
| V | V, V shell, Vala, VB.net, verilog, VHDL, VHS, VimL, vue |
| W | WDTE, WebGPU Shading Language, Whiley |
| X | XML, Xorg |
| Y | YAML, YANG |
| Z | Z80 Assembly, Zed, Zig |
| Prefix | Language
| :----: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| A | ABAP, ABNF, ActionScript, ActionScript 3, Ada, Agda, AL, Alloy, Angular2, ANTLR, ApacheConf, APL, AppleScript, ArangoDB AQL, Arduino, ArmAsm, ATL, AutoHotkey, AutoIt, Awk
| B | Ballerina, Bash, Bash Session, Batchfile, Beef, BibTeX, Bicep, BlitzBasic, BNF, BQN, Brainfuck
| C | C, C#, C++, Caddyfile, Caddyfile Directives, Cap'n Proto, Cassandra CQL, Ceylon, CFEngine3, cfstatement, ChaiScript, Chapel, Cheetah, Clojure, CMake, COBOL, CoffeeScript, Common Lisp, Coq, Core, Crystal, CSS, CSV, CUE, Cython
| D | D, Dart, Dax, Desktop file, Diff, Django/Jinja, dns, Docker, DTD, Dylan
| E | EBNF, Elixir, Elm, EmacsLisp, Erlang
| F | Factor, Fennel, Fish, Forth, Fortran, FortranFixed, FSharp
| G | GAS, GDScript, GDScript3, Gemtext, Genshi, Genshi HTML, Genshi Text, Gherkin, Gleam, GLSL, Gnuplot, Go, Go HTML Template, Go Template, Go Text Template, GraphQL, Groff, Groovy
| H | Handlebars, Hare, Haskell, Haxe, HCL, Hexdump, HLB, HLSL, HolyC, HTML, HTTP, Hy
| I | Idris, Igor, INI, Io, ISCdhcpd
| J | J, Janet, Java, JavaScript, JSON, JSONata, Jsonnet, Julia, Jungle
| K | Kotlin
| L | Lean4, Lighttpd configuration file, LLVM, lox, Lua
| M | Makefile, Mako, markdown, Mason, Materialize SQL dialect, Mathematica, Matlab, MCFunction, Meson, Metal, MiniZinc, MLIR, Modula-2, Mojo, MonkeyC, MoonScript, MorrowindScript, Myghty, MySQL
| N | NASM, Natural, NDISASM, Newspeak, Nginx configuration file, Nim, Nix, NSIS, Nu
| O | Objective-C, ObjectPascal, OCaml, Octave, Odin, OnesEnterprise, OpenEdge ABL, OpenSCAD, Org Mode
| P | PacmanConf, Perl, PHP, PHTML, Pig, PkgConfig, PL/pgSQL, plaintext, Plutus Core, Pony, PostgreSQL SQL dialect, PostScript, POVRay, PowerQuery, PowerShell, Prolog, Promela, PromQL, properties, Protocol Buffer, PRQL, PSL, Puppet, Python, Python 2
| Q | QBasic, QML
| R | R, Racket, Ragel, Raku, react, ReasonML, reg, Rego, reStructuredText, Rexx, RPGLE, RPMSpec, Ruby, Rust
| S | SAS, Sass, Scala, Scheme, Scilab, SCSS, Sed, Sieve, Smali, Smalltalk, Smarty, SNBT, Snobol, Solidity, SourcePawn, SPARQL, SQL, SquidConf, Standard ML, stas, Stylus, Svelte, Swift, SYSTEMD, systemverilog
| T | TableGen, Tal, TASM, Tcl, Tcsh, Termcap, Terminfo, Terraform, TeX, Thrift, TOML, TradingView, Transact-SQL, Turing, Turtle, Twig, TypeScript, TypoScript, TypoScriptCssData, TypoScriptHtmlData, Typst
| U | ucode
| V | V, V shell, Vala, VB.net, verilog, VHDL, VHS, VimL, vue
| W | WDTE, WebGPU Shading Language, WebVTT, Whiley
| X | XML, Xorg
| Y | YAML, YANG
| Z | Z80 Assembly, Zed, Zig
_I will attempt to keep this section up to date, but an authoritative list can be
displayed with `chroma --list`._
@@ -210,8 +214,7 @@ python3 _tools/pygments2chroma_xml.py \
> lexers/embedded/kotlin.xml
```
See notes in [pygments-lexers.txt](https://github.com/alecthomas/chroma/blob/master/pygments-lexers.txt)
for a list of lexers, and notes on some of the issues importing them.
A list of all lexers available in Pygments can be found in [pygments-lexers.txt](https://github.com/alecthomas/chroma/blob/master/pygments-lexers.txt).
### Formatters
@@ -267,6 +270,13 @@ on under the hood for easy integration with [lesspipe shipping with
Debian and derivatives](https://manpages.debian.org/lesspipe#USER_DEFINED_FILTERS);
for that setup the `chroma` executable can be just symlinked to `~/.lessfilter`.
## Projects using Chroma
* [`moar`](https://github.com/walles/moar) is a full-blown pager that colorizes
its input using Chroma
* [Hugo](https://gohugo.io/) is a static site generator that [uses Chroma for syntax
highlighting code examples](https://gohugo.io/content-management/syntax-highlighting/)
## Testing lexers
If you edit some lexers and want to try it, open a shell in `cmd/chromad` and run:
+6
View File
@@ -0,0 +1,6 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.5/schema.json",
"formatter": {
"indentStyle": "space"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

+9
View File
@@ -24,6 +24,15 @@ func DelegatingLexer(root Lexer, language Lexer) Lexer {
}
}
func (d *delegatingLexer) SetTracing(enable bool) {
if l, ok := d.language.(TracingLexer); ok {
l.SetTracing(enable)
}
if l, ok := d.root.(TracingLexer); ok {
l.SetTracing(enable)
}
}
func (d *delegatingLexer) AnalyseText(text string) float32 {
return d.root.AnalyseText(text)
}
+15
View File
@@ -10,6 +10,12 @@ type Emitter interface {
Emit(groups []string, state *LexerState) Iterator
}
// ValidatingEmitter is an Emitter that can validate against a compiled rule.
type ValidatingEmitter interface {
Emitter
ValidateEmitter(rule *CompiledRule) error
}
// SerialisableEmitter is an Emitter that can be serialised and deserialised to/from JSON.
type SerialisableEmitter interface {
Emitter
@@ -30,6 +36,8 @@ type byGroupsEmitter struct {
Emitters
}
var _ ValidatingEmitter = (*byGroupsEmitter)(nil)
// ByGroups emits a token for each matching group in the rule's regex.
func ByGroups(emitters ...Emitter) Emitter {
return &byGroupsEmitter{Emitters: emitters}
@@ -37,6 +45,13 @@ func ByGroups(emitters ...Emitter) Emitter {
func (b *byGroupsEmitter) EmitterKind() string { return "bygroups" }
func (b *byGroupsEmitter) ValidateEmitter(rule *CompiledRule) error {
if len(rule.Regexp.GetGroupNumbers())-1 != len(b.Emitters) {
return fmt.Errorf("number of groups %d does not match number of emitters %d", len(rule.Regexp.GetGroupNumbers())-1, len(b.Emitters))
}
return nil
}
func (b *byGroupsEmitter) Emit(groups []string, state *LexerState) Iterator {
iterators := make([]Iterator, 0, len(groups)-1)
if len(b.Emitters) != len(groups)-1 {
+33 -9
View File
@@ -34,6 +34,9 @@ func WithCustomCSS(css map[chroma.TokenType]string) Option {
}
}
// WithCSSComments adds prefixe comments to the css classes. Defaults to true.
func WithCSSComments(b bool) Option { return func(f *Formatter) { f.writeCSSComments = b } }
// TabWidth sets the number of characters for a tab. Defaults to 8.
func TabWidth(width int) Option { return func(f *Formatter) { f.tabWidth = width } }
@@ -131,8 +134,9 @@ func BaseLineNumber(n int) Option {
// New HTML formatter.
func New(options ...Option) *Formatter {
f := &Formatter{
baseLineNumber: 1,
preWrapper: defaultPreWrapper,
baseLineNumber: 1,
preWrapper: defaultPreWrapper,
writeCSSComments: true,
}
f.styleCache = newStyleCache(f)
for _, option := range options {
@@ -197,6 +201,7 @@ type Formatter struct {
Classes bool // Exported field to detect when classes are being used
allClasses bool
customCSS map[chroma.TokenType]string
writeCSSComments bool
preWrapper PreWrapper
inlineCode bool
preventSurroundingPre bool
@@ -416,21 +421,37 @@ func (f *Formatter) tabWidthStyle() string {
return ""
}
func (f *Formatter) writeCSSRule(w io.Writer, comment string, selector string, styles string) error {
if styles == "" {
return nil
}
if f.writeCSSComments && comment != "" {
if _, err := fmt.Fprintf(w, "/* %s */ ", comment); err != nil {
return err
}
}
if _, err := fmt.Fprintf(w, "%s { %s }\n", selector, styles); err != nil {
return err
}
return nil
}
// WriteCSS writes CSS style definitions (without any surrounding HTML).
func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error {
css := f.styleCache.get(style, false)
// Special-case background as it is mapped to the outer ".chroma" class.
if _, err := fmt.Fprintf(w, "/* %s */ .%sbg { %s }\n", chroma.Background, f.prefix, css[chroma.Background]); err != nil {
if err := f.writeCSSRule(w, chroma.Background.String(), fmt.Sprintf(".%sbg", f.prefix), css[chroma.Background]); err != nil {
return err
}
// Special-case PreWrapper as it is the ".chroma" class.
if _, err := fmt.Fprintf(w, "/* %s */ .%schroma { %s }\n", chroma.PreWrapper, f.prefix, css[chroma.PreWrapper]); err != nil {
if err := f.writeCSSRule(w, chroma.PreWrapper.String(), fmt.Sprintf(".%schroma", f.prefix), css[chroma.PreWrapper]); err != nil {
return err
}
// Special-case code column of table to expand width.
if f.lineNumbers && f.lineNumbersInTable {
if _, err := fmt.Fprintf(w, "/* %s */ .%schroma .%s:last-child { width: 100%%; }",
chroma.LineTableTD, f.prefix, f.class(chroma.LineTableTD)); err != nil {
selector := fmt.Sprintf(".%schroma .%s:last-child", f.prefix, f.class(chroma.LineTableTD))
if err := f.writeCSSRule(w, chroma.LineTableTD.String(), selector, "width: 100%;"); err != nil {
return err
}
}
@@ -438,7 +459,11 @@ func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error {
if f.lineNumbers || f.lineNumbersInTable {
targetedLineCSS := StyleEntryToCSS(style.Get(chroma.LineHighlight))
for _, tt := range []chroma.TokenType{chroma.LineNumbers, chroma.LineNumbersTable} {
fmt.Fprintf(w, "/* %s targeted by URL anchor */ .%schroma .%s:target { %s }\n", tt, f.prefix, f.class(tt), targetedLineCSS)
comment := fmt.Sprintf("%s targeted by URL anchor", tt)
selector := fmt.Sprintf(".%schroma .%s:target", f.prefix, f.class(tt))
if err := f.writeCSSRule(w, comment, selector, targetedLineCSS); err != nil {
return err
}
}
}
tts := []int{}
@@ -456,8 +481,7 @@ func (f *Formatter) WriteCSS(w io.Writer, style *chroma.Style) error {
if class == "" {
continue
}
styles := css[tt]
if _, err := fmt.Fprintf(w, "/* %s */ .%schroma .%s { %s }\n", tt, f.prefix, class, styles); err != nil {
if err := f.writeCSSRule(w, tt.String(), fmt.Sprintf(".%schroma .%s", f.prefix, class), css[tt]); err != nil {
return err
}
}
+11
View File
@@ -18,6 +18,17 @@ func (i Iterator) Tokens() []Token {
return out
}
// Stdlib converts a Chroma iterator to a Go 1.23-compatible iterator.
func (i Iterator) Stdlib() func(yield func(Token) bool) {
return func(yield func(Token) bool) {
for t := i(); t != EOF; t = i() {
if !yield(t) {
return
}
}
}
}
// Concaterator concatenates tokens from a series of iterators.
func Concaterator(iterators ...Iterator) Iterator {
return func() Token {
+17
View File
@@ -130,6 +130,23 @@ type Lexer interface {
AnalyseText(text string) float32
}
// Trace is the trace of a tokenisation process.
type Trace struct {
Lexer string `json:"lexer"`
State string `json:"state"`
Rule int `json:"rule"`
Pattern string `json:"pattern"`
Pos int `json:"pos"`
Length int `json:"length"`
Elapsed float64 `json:"elapsedMs"` // Elapsed time spent matching for this rule.
}
// TracingLexer is a Lexer that can trace its tokenisation process.
type TracingLexer interface {
Lexer
SetTracing(enable bool)
}
// Lexers is a slice of lexers sortable by name.
type Lexers []Lexer
+48 -47
View File
@@ -6,103 +6,104 @@
<rules>
<state name="attr">
<rule pattern="&#34;.*?&#34;">
<token type="LiteralString"/>
<pop depth="1"/>
<token type="LiteralString" />
<pop depth="1" />
</rule>
<rule pattern="&#39;.*?&#39;">
<token type="LiteralString"/>
<pop depth="1"/>
<token type="LiteralString" />
<pop depth="1" />
</rule>
<rule pattern="[^\s&gt;]+">
<token type="LiteralString"/>
<pop depth="1"/>
<token type="LiteralString" />
<pop depth="1" />
</rule>
</state>
<state name="root">
<rule pattern="[^{([*#]+">
<token type="Other"/>
<token type="Other" />
</rule>
<rule pattern="(\{\{)(\s*)">
<bygroups>
<token type="CommentPreproc"/>
<token type="Text"/>
<token type="CommentPreproc" />
<token type="Text" />
</bygroups>
<push state="ngExpression"/>
<push state="ngExpression" />
</rule>
<rule pattern="([([]+)([\w:.-]+)([\])]+)(\s*)(=)(\s*)">
<bygroups>
<token type="Punctuation"/>
<token type="NameAttribute"/>
<token type="Punctuation"/>
<token type="Text"/>
<token type="Operator"/>
<token type="Text"/>
<token type="Punctuation" />
<token type="NameAttribute" />
<token type="Punctuation" />
<token type="Text" />
<token type="Operator" />
<token type="Text" />
</bygroups>
<push state="attr"/>
<push state="attr" />
</rule>
<rule pattern="([([]+)([\w:.-]+)([\])]+)(\s*)">
<bygroups>
<token type="Punctuation"/>
<token type="NameAttribute"/>
<token type="Punctuation"/>
<token type="Text"/>
<token type="Punctuation" />
<token type="NameAttribute" />
<token type="Punctuation" />
<token type="TextWhitespace" />
</bygroups>
</rule>
<rule pattern="([*#])([\w:.-]+)(\s*)(=)(\s*)">
<bygroups>
<token type="Punctuation"/>
<token type="NameAttribute"/>
<token type="Punctuation"/>
<token type="Operator"/>
<token type="Punctuation" />
<token type="NameAttribute" />
<token type="Punctuation" />
<token type="Operator" />
<token type="TextWhitespace" />
</bygroups>
<push state="attr"/>
<push state="attr" />
</rule>
<rule pattern="([*#])([\w:.-]+)(\s*)">
<bygroups>
<token type="Punctuation"/>
<token type="NameAttribute"/>
<token type="Punctuation"/>
<token type="Punctuation" />
<token type="NameAttribute" />
<token type="Punctuation" />
</bygroups>
</rule>
</state>
<state name="ngExpression">
<rule pattern="\s+(\|\s+)?">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="\}\}">
<token type="CommentPreproc"/>
<pop depth="1"/>
<token type="CommentPreproc" />
<pop depth="1" />
</rule>
<rule pattern=":?(true|false)">
<token type="LiteralStringBoolean"/>
<token type="LiteralStringBoolean" />
</rule>
<rule pattern=":?&#34;(\\\\|\\&#34;|[^&#34;])*&#34;">
<token type="LiteralStringDouble"/>
<token type="LiteralStringDouble" />
</rule>
<rule pattern=":?&#39;(\\\\|\\&#39;|[^&#39;])*&#39;">
<token type="LiteralStringSingle"/>
<token type="LiteralStringSingle" />
</rule>
<rule pattern="[0-9](\.[0-9]*)?(eE[+-][0-9])?[flFLdD]?|0[xX][0-9a-fA-F]+[Ll]?">
<token type="LiteralNumber"/>
<token type="LiteralNumber" />
</rule>
<rule pattern="[a-zA-Z][\w-]*(\(.*\))?">
<token type="NameVariable"/>
<token type="NameVariable" />
</rule>
<rule pattern="\.[\w-]+(\(.*\))?">
<token type="NameVariable"/>
<token type="NameVariable" />
</rule>
<rule pattern="(\?)(\s*)([^}\s]+)(\s*)(:)(\s*)([^}\s]+)(\s*)">
<bygroups>
<token type="Operator"/>
<token type="Text"/>
<token type="LiteralString"/>
<token type="Text"/>
<token type="Operator"/>
<token type="Text"/>
<token type="LiteralString"/>
<token type="Text"/>
<token type="Operator" />
<token type="Text" />
<token type="LiteralString" />
<token type="Text" />
<token type="Operator" />
<token type="Text" />
<token type="LiteralString" />
<token type="Text" />
</bygroups>
</rule>
</state>
</rules>
</lexer>
</lexer>
@@ -8,123 +8,144 @@
<rules>
<state name="root">
<rule pattern="\s+">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="¬\n">
<token type="LiteralStringEscape"/>
<token type="LiteralStringEscape" />
</rule>
<rule pattern="&#39;s\s+">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="(--|#).*?$">
<token type="Comment"/>
<token type="Comment" />
</rule>
<rule pattern="\(\*">
<token type="CommentMultiline"/>
<push state="comment"/>
<token type="CommentMultiline" />
<push state="comment" />
</rule>
<rule pattern="[(){}!,.:]">
<token type="Punctuation"/>
<token type="Punctuation" />
</rule>
<rule pattern="(«)([^»]+)(»)">
<bygroups>
<token type="Text"/>
<token type="NameBuiltin"/>
<token type="Text"/>
<token type="Text" />
<token type="NameBuiltin" />
<token type="Text" />
</bygroups>
</rule>
<rule pattern="\b((?:considering|ignoring)\s*)(application responses|case|diacriticals|hyphens|numeric strings|punctuation|white space)">
<rule
pattern="\b((?:considering|ignoring)\s*)(application responses|case|diacriticals|hyphens|numeric strings|punctuation|white space)"
>
<bygroups>
<token type="Keyword"/>
<token type="NameBuiltin"/>
<token type="Keyword" />
<token type="NameBuiltin" />
</bygroups>
</rule>
<rule pattern="(-|\*|\+|&amp;|≠|&gt;=?|&lt;=?|=|≥|≤|/|÷|\^)">
<token type="Operator"/>
<token type="Operator" />
</rule>
<rule pattern="\b(and|or|is equal|equals|(is )?equal to|is not|isn&#39;t|isn&#39;t equal( to)?|is not equal( to)?|doesn&#39;t equal|does not equal|(is )?greater than|comes after|is not less than or equal( to)?|isn&#39;t less than or equal( to)?|(is )?less than|comes before|is not greater than or equal( to)?|isn&#39;t greater than or equal( to)?|(is )?greater than or equal( to)?|is not less than|isn&#39;t less than|does not come before|doesn&#39;t come before|(is )?less than or equal( to)?|is not greater than|isn&#39;t greater than|does not come after|doesn&#39;t come after|starts? with|begins? with|ends? with|contains?|does not contain|doesn&#39;t contain|is in|is contained by|is not in|is not contained by|isn&#39;t contained by|div|mod|not|(a )?(ref( to)?|reference to)|is|does)\b">
<token type="OperatorWord"/>
<rule
pattern="\b(and|or|is equal|equals|(is )?equal to|is not|isn&#39;t|isn&#39;t equal( to)?|is not equal( to)?|doesn&#39;t equal|does not equal|(is )?greater than|comes after|is not less than or equal( to)?|isn&#39;t less than or equal( to)?|(is )?less than|comes before|is not greater than or equal( to)?|isn&#39;t greater than or equal( to)?|(is )?greater than or equal( to)?|is not less than|isn&#39;t less than|does not come before|doesn&#39;t come before|(is )?less than or equal( to)?|is not greater than|isn&#39;t greater than|does not come after|doesn&#39;t come after|starts? with|begins? with|ends? with|contains?|does not contain|doesn&#39;t contain|is in|is contained by|is not in|is not contained by|isn&#39;t contained by|div|mod|not|(a )?(ref( to)?|reference to)|is|does)\b"
>
<token type="OperatorWord" />
</rule>
<rule pattern="^(\s*(?:on|end)\s+)(zoomed|write to file|will zoom|will show|will select tab view item|will resize( sub views)?|will resign active|will quit|will pop up|will open|will move|will miniaturize|will hide|will finish launching|will display outline cell|will display item cell|will display cell|will display browser cell|will dismiss|will close|will become active|was miniaturized|was hidden|update toolbar item|update parameters|update menu item|shown|should zoom|should selection change|should select tab view item|should select row|should select item|should select column|should quit( after last window closed)?|should open( untitled)?|should expand item|should end editing|should collapse item|should close|should begin editing|selection changing|selection changed|selected tab view item|scroll wheel|rows changed|right mouse up|right mouse dragged|right mouse down|resized( sub views)?|resigned main|resigned key|resigned active|read from file|prepare table drop|prepare table drag|prepare outline drop|prepare outline drag|prepare drop|plugin loaded|parameters updated|panel ended|opened|open untitled|number of rows|number of items|number of browser rows|moved|mouse up|mouse moved|mouse exited|mouse entered|mouse dragged|mouse down|miniaturized|load data representation|launched|keyboard up|keyboard down|items changed|item value changed|item value|item expandable|idle|exposed|end editing|drop|drag( (entered|exited|updated))?|double clicked|document nib name|dialog ended|deminiaturized|data representation|conclude drop|column resized|column moved|column clicked|closed|clicked toolbar item|clicked|choose menu item|child of item|changed|change item value|change cell value|cell value changed|cell value|bounds changed|begin editing|became main|became key|awake from nib|alert ended|activated|action|accept table drop|accept outline drop)">
<bygroups>
<token type="Keyword"/>
<token type="NameFunction"/>
</bygroups>
<rule
pattern="^(\s*(?:on|end)\s+)(zoomed|write to file|will zoom|will show|will select tab view item|will resize( sub views)?|will resign active|will quit|will pop up|will open|will move|will miniaturize|will hide|will finish launching|will display outline cell|will display item cell|will display cell|will display browser cell|will dismiss|will close|will become active|was miniaturized|was hidden|update toolbar item|update parameters|update menu item|shown|should zoom|should selection change|should select tab view item|should select row|should select item|should select column|should quit( after last window closed)?|should open( untitled)?|should expand item|should end editing|should collapse item|should close|should begin editing|selection changing|selection changed|selected tab view item|scroll wheel|rows changed|right mouse up|right mouse dragged|right mouse down|resized( sub views)?|resigned main|resigned key|resigned active|read from file|prepare table drop|prepare table drag|prepare outline drop|prepare outline drag|prepare drop|plugin loaded|parameters updated|panel ended|opened|open untitled|number of rows|number of items|number of browser rows|moved|mouse up|mouse moved|mouse exited|mouse entered|mouse dragged|mouse down|miniaturized|load data representation|launched|keyboard up|keyboard down|items changed|item value changed|item value|item expandable|idle|exposed|end editing|drop|drag( (entered|exited|updated))?|double clicked|document nib name|dialog ended|deminiaturized|data representation|conclude drop|column resized|column moved|column clicked|closed|clicked toolbar item|clicked|choose menu item|child of item|changed|change item value|change cell value|cell value changed|cell value|bounds changed|begin editing|became main|became key|awake from nib|alert ended|activated|action|accept table drop|accept outline drop)"
>
<token type="Keyword" />
</rule>
<rule pattern="^(\s*)(in|on|script|to)(\s+)">
<bygroups>
<token type="Text"/>
<token type="Keyword"/>
<token type="Text"/>
<token type="Text" />
<token type="Keyword" />
<token type="Text" />
</bygroups>
</rule>
<rule pattern="\b(as )(alias |application |boolean |class |constant |date |file |integer |list |number |POSIX file |real |record |reference |RGB color |script |text |unit types|(?:Unicode )?text|string)\b">
<rule
pattern="\b(as )(alias |application |boolean |class |constant |date |file |integer |list |number |POSIX file |real |record |reference |RGB color |script |text |unit types|(?:Unicode )?text|string)\b"
>
<bygroups>
<token type="Keyword"/>
<token type="NameClass"/>
<token type="Keyword" />
<token type="NameClass" />
</bygroups>
</rule>
<rule pattern="\b(AppleScript|current application|false|linefeed|missing value|pi|quote|result|return|space|tab|text item delimiters|true|version)\b">
<token type="NameConstant"/>
<rule
pattern="\b(AppleScript|current application|false|linefeed|missing value|pi|quote|result|return|space|tab|text item delimiters|true|version)\b"
>
<token type="NameConstant" />
</rule>
<rule pattern="\b(ASCII (character|number)|activate|beep|choose URL|choose application|choose color|choose file( name)?|choose folder|choose from list|choose remote application|clipboard info|close( access)?|copy|count|current date|delay|delete|display (alert|dialog)|do shell script|duplicate|exists|get eof|get volume settings|info for|launch|list (disks|folder)|load script|log|make|mount volume|new|offset|open( (for access|location))?|path to|print|quit|random number|read|round|run( script)?|say|scripting components|set (eof|the clipboard to|volume)|store script|summarize|system attribute|system info|the clipboard|time to GMT|write|quoted form)\b">
<token type="NameBuiltin"/>
<rule
pattern="\b(ASCII (character|number)|activate|beep|choose URL|choose application|choose color|choose file( name)?|choose folder|choose from list|choose remote application|clipboard info|close( access)?|copy|count|current date|delay|delete|display (alert|dialog)|do shell script|duplicate|exists|get eof|get volume settings|info for|launch|list (disks|folder)|load script|log|make|mount volume|new|offset|open( (for access|location))?|path to|print|quit|random number|read|round|run( script)?|say|scripting components|set (eof|the clipboard to|volume)|store script|summarize|system attribute|system info|the clipboard|time to GMT|write|quoted form)\b"
>
<token type="NameBuiltin" />
</rule>
<rule pattern="\b(considering|else|error|exit|from|if|ignoring|in|repeat|tell|then|times|to|try|until|using terms from|while|with|with timeout( of)?|with transaction|by|continue|end|its?|me|my|return|of|as)\b">
<token type="Keyword"/>
<rule
pattern="\b(considering|else|error|exit|from|if|ignoring|in|repeat|tell|then|times|to|try|until|using terms from|while|with|with timeout( of)?|with transaction|by|continue|end|its?|me|my|return|of|as)\b"
>
<token type="Keyword" />
</rule>
<rule pattern="\b(global|local|prop(erty)?|set|get)\b">
<token type="Keyword"/>
<token type="Keyword" />
</rule>
<rule pattern="\b(but|put|returning|the)\b">
<token type="NameBuiltin"/>
<token type="NameBuiltin" />
</rule>
<rule pattern="\b(attachment|attribute run|character|day|month|paragraph|word|year)s?\b">
<token type="NameBuiltin"/>
<token type="NameBuiltin" />
</rule>
<rule pattern="\b(about|above|against|apart from|around|aside from|at|below|beneath|beside|between|for|given|instead of|on|onto|out of|over|since)\b">
<token type="NameBuiltin"/>
<rule
pattern="\b(about|above|against|apart from|around|aside from|at|below|beneath|beside|between|for|given|instead of|on|onto|out of|over|since)\b"
>
<token type="NameBuiltin" />
</rule>
<rule pattern="\b(accepts arrow key|action method|active|alignment|allowed identifiers|allows branch selection|allows column reordering|allows column resizing|allows column selection|allows customization|allows editing text attributes|allows empty selection|allows mixed state|allows multiple selection|allows reordering|allows undo|alpha( value)?|alternate image|alternate increment value|alternate title|animation delay|associated file name|associated object|auto completes|auto display|auto enables items|auto repeat|auto resizes( outline column)?|auto save expanded items|auto save name|auto save table columns|auto saves configuration|auto scroll|auto sizes all columns to fit|auto sizes cells|background color|bezel state|bezel style|bezeled|border rect|border type|bordered|bounds( rotation)?|box type|button returned|button type|can choose directories|can choose files|can draw|can hide|cell( (background color|size|type))?|characters|class|click count|clicked( data)? column|clicked data item|clicked( data)? row|closeable|collating|color( (mode|panel))|command key down|configuration|content(s| (size|view( margins)?))?|context|continuous|control key down|control size|control tint|control view|controller visible|coordinate system|copies( on scroll)?|corner view|current cell|current column|current( field)? editor|current( menu)? item|current row|current tab view item|data source|default identifiers|delta (x|y|z)|destination window|directory|display mode|displayed cell|document( (edited|rect|view))?|double value|dragged column|dragged distance|dragged items|draws( cell)? background|draws grid|dynamically scrolls|echos bullets|edge|editable|edited( data)? column|edited data item|edited( data)? row|enabled|enclosing scroll view|ending page|error handling|event number|event type|excluded from windows menu|executable path|expanded|fax number|field editor|file kind|file name|file type|first responder|first visible column|flipped|floating|font( panel)?|formatter|frameworks path|frontmost|gave up|grid color|has data items|has horizontal ruler|has horizontal scroller|has parent data item|has resize indicator|has shadow|has sub menu|has vertical ruler|has vertical scroller|header cell|header view|hidden|hides when deactivated|highlights by|horizontal line scroll|horizontal page scroll|horizontal ruler view|horizontally resizable|icon image|id|identifier|ignores multiple clicks|image( (alignment|dims when disabled|frame style|scaling))?|imports graphics|increment value|indentation per level|indeterminate|index|integer value|intercell spacing|item height|key( (code|equivalent( modifier)?|window))?|knob thickness|label|last( visible)? column|leading offset|leaf|level|line scroll|loaded|localized sort|location|loop mode|main( (bunde|menu|window))?|marker follows cell|matrix mode|maximum( content)? size|maximum visible columns|menu( form representation)?|miniaturizable|miniaturized|minimized image|minimized title|minimum column width|minimum( content)? size|modal|modified|mouse down state|movie( (controller|file|rect))?|muted|name|needs display|next state|next text|number of tick marks|only tick mark values|opaque|open panel|option key down|outline table column|page scroll|pages across|pages down|palette label|pane splitter|parent data item|parent window|pasteboard|path( (names|separator))?|playing|plays every frame|plays selection only|position|preferred edge|preferred type|pressure|previous text|prompt|properties|prototype cell|pulls down|rate|released when closed|repeated|requested print time|required file type|resizable|resized column|resource path|returns records|reuses columns|rich text|roll over|row height|rulers visible|save panel|scripts path|scrollable|selectable( identifiers)?|selected cell|selected( data)? columns?|selected data items?|selected( data)? rows?|selected item identifier|selection by rect|send action on arrow key|sends action when done editing|separates columns|separator item|sequence number|services menu|shared frameworks path|shared support path|sheet|shift key down|shows alpha|shows state by|size( mode)?|smart insert delete enabled|sort case sensitivity|sort column|sort order|sort type|sorted( data rows)?|sound|source( mask)?|spell checking enabled|starting page|state|string value|sub menu|super menu|super view|tab key traverses cells|tab state|tab type|tab view|table view|tag|target( printer)?|text color|text container insert|text container origin|text returned|tick mark position|time stamp|title(d| (cell|font|height|position|rect))?|tool tip|toolbar|trailing offset|transparent|treat packages as directories|truncated labels|types|unmodified characters|update views|use sort indicator|user defaults|uses data source|uses ruler|uses threaded animation|uses title from previous column|value wraps|version|vertical( (line scroll|page scroll|ruler view))?|vertically resizable|view|visible( document rect)?|volume|width|window|windows menu|wraps|zoomable|zoomed)\b">
<token type="NameAttribute"/>
<rule
pattern="\b(accepts arrow key|action method|active|alignment|allowed identifiers|allows branch selection|allows column reordering|allows column resizing|allows column selection|allows customization|allows editing text attributes|allows empty selection|allows mixed state|allows multiple selection|allows reordering|allows undo|alpha( value)?|alternate image|alternate increment value|alternate title|animation delay|associated file name|associated object|auto completes|auto display|auto enables items|auto repeat|auto resizes( outline column)?|auto save expanded items|auto save name|auto save table columns|auto saves configuration|auto scroll|auto sizes all columns to fit|auto sizes cells|background color|bezel state|bezel style|bezeled|border rect|border type|bordered|bounds( rotation)?|box type|button returned|button type|can choose directories|can choose files|can draw|can hide|cell( (background color|size|type))?|characters|class|click count|clicked( data)? column|clicked data item|clicked( data)? row|closeable|collating|color( (mode|panel))|command key down|configuration|content(s| (size|view( margins)?))?|context|continuous|control key down|control size|control tint|control view|controller visible|coordinate system|copies( on scroll)?|corner view|current cell|current column|current( field)? editor|current( menu)? item|current row|current tab view item|data source|default identifiers|delta (x|y|z)|destination window|directory|display mode|displayed cell|document( (edited|rect|view))?|double value|dragged column|dragged distance|dragged items|draws( cell)? background|draws grid|dynamically scrolls|echos bullets|edge|editable|edited( data)? column|edited data item|edited( data)? row|enabled|enclosing scroll view|ending page|error handling|event number|event type|excluded from windows menu|executable path|expanded|fax number|field editor|file kind|file name|file type|first responder|first visible column|flipped|floating|font( panel)?|formatter|frameworks path|frontmost|gave up|grid color|has data items|has horizontal ruler|has horizontal scroller|has parent data item|has resize indicator|has shadow|has sub menu|has vertical ruler|has vertical scroller|header cell|header view|hidden|hides when deactivated|highlights by|horizontal line scroll|horizontal page scroll|horizontal ruler view|horizontally resizable|icon image|id|identifier|ignores multiple clicks|image( (alignment|dims when disabled|frame style|scaling))?|imports graphics|increment value|indentation per level|indeterminate|index|integer value|intercell spacing|item height|key( (code|equivalent( modifier)?|window))?|knob thickness|label|last( visible)? column|leading offset|leaf|level|line scroll|loaded|localized sort|location|loop mode|main( (bunde|menu|window))?|marker follows cell|matrix mode|maximum( content)? size|maximum visible columns|menu( form representation)?|miniaturizable|miniaturized|minimized image|minimized title|minimum column width|minimum( content)? size|modal|modified|mouse down state|movie( (controller|file|rect))?|muted|name|needs display|next state|next text|number of tick marks|only tick mark values|opaque|open panel|option key down|outline table column|page scroll|pages across|pages down|palette label|pane splitter|parent data item|parent window|pasteboard|path( (names|separator))?|playing|plays every frame|plays selection only|position|preferred edge|preferred type|pressure|previous text|prompt|properties|prototype cell|pulls down|rate|released when closed|repeated|requested print time|required file type|resizable|resized column|resource path|returns records|reuses columns|rich text|roll over|row height|rulers visible|save panel|scripts path|scrollable|selectable( identifiers)?|selected cell|selected( data)? columns?|selected data items?|selected( data)? rows?|selected item identifier|selection by rect|send action on arrow key|sends action when done editing|separates columns|separator item|sequence number|services menu|shared frameworks path|shared support path|sheet|shift key down|shows alpha|shows state by|size( mode)?|smart insert delete enabled|sort case sensitivity|sort column|sort order|sort type|sorted( data rows)?|sound|source( mask)?|spell checking enabled|starting page|state|string value|sub menu|super menu|super view|tab key traverses cells|tab state|tab type|tab view|table view|tag|target( printer)?|text color|text container insert|text container origin|text returned|tick mark position|time stamp|title(d| (cell|font|height|position|rect))?|tool tip|toolbar|trailing offset|transparent|treat packages as directories|truncated labels|types|unmodified characters|update views|use sort indicator|user defaults|uses data source|uses ruler|uses threaded animation|uses title from previous column|value wraps|version|vertical( (line scroll|page scroll|ruler view))?|vertically resizable|view|visible( document rect)?|volume|width|window|windows menu|wraps|zoomable|zoomed)\b"
>
<token type="NameAttribute" />
</rule>
<rule pattern="\b(action cell|alert reply|application|box|browser( cell)?|bundle|button( cell)?|cell|clip view|color well|color-panel|combo box( item)?|control|data( (cell|column|item|row|source))?|default entry|dialog reply|document|drag info|drawer|event|font(-panel)?|formatter|image( (cell|view))?|matrix|menu( item)?|item|movie( view)?|open-panel|outline view|panel|pasteboard|plugin|popup button|progress indicator|responder|save-panel|scroll view|secure text field( cell)?|slider|sound|split view|stepper|tab view( item)?|table( (column|header cell|header view|view))|text( (field( cell)?|view))?|toolbar( item)?|user-defaults|view|window)s?\b">
<token type="NameBuiltin"/>
<rule
pattern="\b(action cell|alert reply|application|box|browser( cell)?|bundle|button( cell)?|cell|clip view|color well|color-panel|combo box( item)?|control|data( (cell|column|item|row|source))?|default entry|dialog reply|document|drag info|drawer|event|font(-panel)?|formatter|image( (cell|view))?|matrix|menu( item)?|item|movie( view)?|open-panel|outline view|panel|pasteboard|plugin|popup button|progress indicator|responder|save-panel|scroll view|secure text field( cell)?|slider|sound|split view|stepper|tab view( item)?|table( (column|header cell|header view|view))|text( (field( cell)?|view))?|toolbar( item)?|user-defaults|view|window)s?\b"
>
<token type="NameBuiltin" />
</rule>
<rule pattern="\b(animate|append|call method|center|close drawer|close panel|display|display alert|display dialog|display panel|go|hide|highlight|increment|item for|load image|load movie|load nib|load panel|load sound|localized string|lock focus|log|open drawer|path for|pause|perform action|play|register|resume|scroll|select( all)?|show|size to fit|start|step back|step forward|stop|synchronize|unlock focus|update)\b">
<token type="NameBuiltin"/>
<rule
pattern="\b(animate|append|call method|center|close drawer|close panel|display|display alert|display dialog|display panel|go|hide|highlight|increment|item for|load image|load movie|load nib|load panel|load sound|localized string|lock focus|log|open drawer|path for|pause|perform action|play|register|resume|scroll|select( all)?|show|size to fit|start|step back|step forward|stop|synchronize|unlock focus|update)\b"
>
<token type="NameBuiltin" />
</rule>
<rule pattern="\b((in )?back of|(in )?front of|[0-9]+(st|nd|rd|th)|first|second|third|fourth|fifth|sixth|seventh|eighth|ninth|tenth|after|back|before|behind|every|front|index|last|middle|some|that|through|thru|where|whose)\b">
<token type="NameBuiltin"/>
<rule
pattern="\b((in )?back of|(in )?front of|[0-9]+(st|nd|rd|th)|first|second|third|fourth|fifth|sixth|seventh|eighth|ninth|tenth|after|back|before|behind|every|front|index|last|middle|some|that|through|thru|where|whose)\b"
>
<token type="NameBuiltin" />
</rule>
<rule pattern="&#34;(\\\\|\\&#34;|[^&#34;])*&#34;">
<token type="LiteralStringDouble"/>
<token type="LiteralStringDouble" />
</rule>
<rule pattern="\b([a-zA-Z]\w*)\b">
<token type="NameVariable"/>
<token type="NameVariable" />
</rule>
<rule pattern="[-+]?(\d+\.\d*|\d*\.\d+)(E[-+][0-9]+)?">
<token type="LiteralNumberFloat"/>
<token type="LiteralNumberFloat" />
</rule>
<rule pattern="[-+]?\d+">
<token type="LiteralNumberInteger"/>
<token type="LiteralNumberInteger" />
</rule>
</state>
<state name="comment">
<rule pattern="\(\*">
<token type="CommentMultiline"/>
<push/>
<token type="CommentMultiline" />
<push />
</rule>
<rule pattern="\*\)">
<token type="CommentMultiline"/>
<pop depth="1"/>
<token type="CommentMultiline" />
<pop depth="1" />
</rule>
<rule pattern="[^*(]+">
<token type="CommentMultiline"/>
<token type="CommentMultiline" />
</rule>
<rule pattern="[*(]">
<token type="CommentMultiline"/>
<token type="CommentMultiline" />
</rule>
</state>
</rules>
</lexer>
</lexer>
+137 -124
View File
@@ -9,301 +9,314 @@
<rules>
<state name="whitespace">
<rule pattern="^#if\s+0">
<token type="CommentPreproc"/>
<push state="if0"/>
<token type="CommentPreproc" />
<push state="if0" />
</rule>
<rule pattern="^#">
<token type="CommentPreproc"/>
<push state="macro"/>
<token type="CommentPreproc" />
<push state="macro" />
</rule>
<rule pattern="^(\s*(?:/[*].*?[*]/\s*)?)(#if\s+0)">
<bygroups>
<usingself state="root"/>
<token type="CommentPreproc"/>
<usingself state="root" />
<token type="CommentPreproc" />
</bygroups>
<push state="if0"/>
<push state="if0" />
</rule>
<rule pattern="^(\s*(?:/[*].*?[*]/\s*)?)(#)">
<bygroups>
<usingself state="root"/>
<token type="CommentPreproc"/>
<usingself state="root" />
<token type="CommentPreproc" />
</bygroups>
<push state="macro"/>
<push state="macro" />
</rule>
<rule pattern="\n">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="\s+">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="\\\n">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="//(\n|[\w\W]*?[^\\]\n)">
<token type="CommentSingle"/>
<token type="CommentSingle" />
</rule>
<rule pattern="/(\\\n)?[*][\w\W]*?[*](\\\n)?/">
<token type="CommentMultiline"/>
<token type="CommentMultiline" />
</rule>
<rule pattern="/(\\\n)?[*][\w\W]*">
<token type="CommentMultiline"/>
<token type="CommentMultiline" />
</rule>
</state>
<state name="string">
<rule pattern="&#34;">
<token type="LiteralString"/>
<pop depth="1"/>
<token type="LiteralString" />
<pop depth="1" />
</rule>
<rule pattern="\\([\\abfnrtv&#34;\&#39;]|x[a-fA-F0-9]{2,4}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8}|[0-7]{1,3})">
<token type="LiteralStringEscape"/>
<token type="LiteralStringEscape" />
</rule>
<rule pattern="[^\\&#34;\n]+">
<token type="LiteralString"/>
<token type="LiteralString" />
</rule>
<rule pattern="\\\n">
<token type="LiteralString"/>
<token type="LiteralString" />
</rule>
<rule pattern="\\">
<token type="LiteralString"/>
<token type="LiteralString" />
</rule>
</state>
<state name="macro">
<rule pattern="(include)(\s*(?:/[*].*?[*]/\s*)?)([^\n]+)">
<bygroups>
<token type="CommentPreproc"/>
<token type="Text"/>
<token type="CommentPreprocFile"/>
<token type="CommentPreproc" />
<token type="Text" />
<token type="CommentPreprocFile" />
</bygroups>
</rule>
<rule pattern="[^/\n]+">
<token type="CommentPreproc"/>
<token type="CommentPreproc" />
</rule>
<rule pattern="/[*](.|\n)*?[*]/">
<token type="CommentMultiline"/>
<token type="CommentMultiline" />
</rule>
<rule pattern="//.*?\n">
<token type="CommentSingle"/>
<pop depth="1"/>
<token type="CommentSingle" />
<pop depth="1" />
</rule>
<rule pattern="/">
<token type="CommentPreproc"/>
<token type="CommentPreproc" />
</rule>
<rule pattern="(?&lt;=\\)\n">
<token type="CommentPreproc"/>
<token type="CommentPreproc" />
</rule>
<rule pattern="\n">
<token type="CommentPreproc"/>
<pop depth="1"/>
<token type="CommentPreproc" />
<pop depth="1" />
</rule>
</state>
<state name="statements">
<rule pattern="(reinterpret_cast|static_assert|dynamic_cast|thread_local|static_cast|const_cast|protected|constexpr|namespace|restrict|noexcept|override|operator|typename|template|explicit|decltype|nullptr|private|alignof|virtual|mutable|alignas|typeid|friend|throws|export|public|delete|final|using|throw|catch|this|try|new)\b">
<token type="Keyword"/>
<rule
pattern="(reinterpret_cast|static_assert|dynamic_cast|thread_local|static_cast|const_cast|protected|constexpr|namespace|restrict|noexcept|override|operator|typename|template|explicit|decltype|nullptr|private|alignof|virtual|mutable|alignas|typeid|friend|throws|export|public|delete|final|using|throw|catch|this|try|new)\b"
>
<token type="Keyword" />
</rule>
<rule pattern="char(16_t|32_t)\b">
<token type="KeywordType"/>
<token type="KeywordType" />
</rule>
<rule pattern="(class)\b">
<bygroups>
<token type="Keyword"/>
<token type="Text"/>
<token type="Keyword" />
</bygroups>
<push state="classname"/>
<push state="classname" />
</rule>
<rule pattern="(R)(&#34;)([^\\()\s]{,16})(\()((?:.|\n)*?)(\)\3)(&#34;)">
<bygroups>
<token type="LiteralStringAffix"/>
<token type="LiteralString"/>
<token type="LiteralStringDelimiter"/>
<token type="LiteralStringDelimiter"/>
<token type="LiteralString"/>
<token type="LiteralStringDelimiter"/>
<token type="LiteralString"/>
<token type="LiteralStringAffix" />
<token type="LiteralString" />
<token type="LiteralStringDelimiter" />
<token type="LiteralStringDelimiter" />
<token type="LiteralString" />
<token type="LiteralStringDelimiter" />
<token type="LiteralString" />
</bygroups>
</rule>
<rule pattern="(u8|u|U)(&#34;)">
<bygroups>
<token type="LiteralStringAffix"/>
<token type="LiteralString"/>
<token type="LiteralStringAffix" />
<token type="LiteralString" />
</bygroups>
<push state="string"/>
<push state="string" />
</rule>
<rule pattern="(L?)(&#34;)">
<bygroups>
<token type="LiteralStringAffix"/>
<token type="LiteralString"/>
<token type="LiteralStringAffix" />
<token type="LiteralString" />
</bygroups>
<push state="string"/>
<push state="string" />
</rule>
<rule pattern="(L?)(&#39;)(\\.|\\[0-7]{1,3}|\\x[a-fA-F0-9]{1,2}|[^\\\&#39;\n])(&#39;)">
<bygroups>
<token type="LiteralStringAffix"/>
<token type="LiteralStringChar"/>
<token type="LiteralStringChar"/>
<token type="LiteralStringChar"/>
<token type="LiteralStringAffix" />
<token type="LiteralStringChar" />
<token type="LiteralStringChar" />
<token type="LiteralStringChar" />
</bygroups>
</rule>
<rule pattern="(\d+\.\d*|\.\d+|\d+)[eE][+-]?\d+[LlUu]*">
<token type="LiteralNumberFloat"/>
<token type="LiteralNumberFloat" />
</rule>
<rule pattern="(\d+\.\d*|\.\d+|\d+[fF])[fF]?">
<token type="LiteralNumberFloat"/>
<token type="LiteralNumberFloat" />
</rule>
<rule pattern="0x[0-9a-fA-F]+[LlUu]*">
<token type="LiteralNumberHex"/>
<token type="LiteralNumberHex" />
</rule>
<rule pattern="0[0-7]+[LlUu]*">
<token type="LiteralNumberOct"/>
<token type="LiteralNumberOct" />
</rule>
<rule pattern="\d+[LlUu]*">
<token type="LiteralNumberInteger"/>
<token type="LiteralNumberInteger" />
</rule>
<rule pattern="\*/">
<token type="Error"/>
<token type="Error" />
</rule>
<rule pattern="[~!%^&amp;*+=|?:&lt;&gt;/-]">
<token type="Operator"/>
<token type="Operator" />
</rule>
<rule pattern="[()\[\],.]">
<token type="Punctuation"/>
<token type="Punctuation" />
</rule>
<rule pattern="(restricted|volatile|continue|register|default|typedef|struct|extern|switch|sizeof|static|return|union|while|const|break|goto|enum|else|case|auto|for|asm|if|do)\b">
<token type="Keyword"/>
<rule
pattern="(restricted|volatile|continue|register|default|typedef|struct|extern|switch|sizeof|static|return|union|while|const|break|goto|enum|else|case|auto|for|asm|if|do)\b"
>
<token type="Keyword" />
</rule>
<rule pattern="(_Bool|_Complex|_Imaginary|array|atomic_bool|atomic_char|atomic_int|atomic_llong|atomic_long|atomic_schar|atomic_short|atomic_uchar|atomic_uint|atomic_ullong|atomic_ulong|atomic_ushort|auto|bool|boolean|BooleanVariables|Byte|byte|Char|char|char16_t|char32_t|class|complex|Const|const|const_cast|delete|double|dynamic_cast|enum|explicit|extern|Float|float|friend|inline|Int|int|int16_t|int32_t|int64_t|int8_t|Long|long|new|NULL|null|operator|private|PROGMEM|protected|public|register|reinterpret_cast|short|signed|sizeof|Static|static|static_cast|String|struct|typedef|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|virtual|Void|void|Volatile|volatile|word)\b">
<token type="KeywordType"/>
<rule
pattern="(_Bool|_Complex|_Imaginary|array|atomic_bool|atomic_char|atomic_int|atomic_llong|atomic_long|atomic_schar|atomic_short|atomic_uchar|atomic_uint|atomic_ullong|atomic_ulong|atomic_ushort|auto|bool|boolean|BooleanVariables|Byte|byte|Char|char|char16_t|char32_t|class|complex|Const|const|const_cast|delete|double|dynamic_cast|enum|explicit|extern|Float|float|friend|inline|Int|int|int16_t|int32_t|int64_t|int8_t|Long|long|new|NULL|null|operator|private|PROGMEM|protected|public|register|reinterpret_cast|short|signed|sizeof|Static|static|static_cast|String|struct|typedef|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|virtual|Void|void|Volatile|volatile|word)\b"
>
<token type="KeywordType" />
</rule>
<rule pattern="(and|final|If|Loop|loop|not|or|override|setup|Setup|throw|try|xor)\b">
<token type="Keyword"/>
<token type="Keyword" />
</rule>
<rule pattern="(ANALOG_MESSAGE|BIN|CHANGE|DEC|DEFAULT|DIGITAL_MESSAGE|EXTERNAL|FALLING|FIRMATA_STRING|HALF_PI|HEX|HIGH|INPUT|INPUT_PULLUP|INTERNAL|INTERNAL1V1|INTERNAL1V1|INTERNAL2V56|INTERNAL2V56|LED_BUILTIN|LED_BUILTIN_RX|LED_BUILTIN_TX|LOW|LSBFIRST|MSBFIRST|OCT|OUTPUT|PI|REPORT_ANALOG|REPORT_DIGITAL|RISING|SET_PIN_MODE|SYSEX_START|SYSTEM_RESET|TWO_PI)\b">
<token type="KeywordConstant"/>
<rule
pattern="(ANALOG_MESSAGE|BIN|CHANGE|DEC|DEFAULT|DIGITAL_MESSAGE|EXTERNAL|FALLING|FIRMATA_STRING|HALF_PI|HEX|HIGH|INPUT|INPUT_PULLUP|INTERNAL|INTERNAL1V1|INTERNAL1V1|INTERNAL2V56|INTERNAL2V56|LED_BUILTIN|LED_BUILTIN_RX|LED_BUILTIN_TX|LOW|LSBFIRST|MSBFIRST|OCT|OUTPUT|PI|REPORT_ANALOG|REPORT_DIGITAL|RISING|SET_PIN_MODE|SYSEX_START|SYSTEM_RESET|TWO_PI)\b"
>
<token type="KeywordConstant" />
</rule>
<rule pattern="(boolean|const|byte|word|string|String|array)\b">
<token type="NameVariable"/>
<token type="NameVariable" />
</rule>
<rule pattern="(Keyboard|KeyboardController|MouseController|SoftwareSerial|EthernetServer|EthernetClient|LiquidCrystal|RobotControl|GSMVoiceCall|EthernetUDP|EsploraTFT|HttpClient|RobotMotor|WiFiClient|GSMScanner|FileSystem|Scheduler|GSMServer|YunClient|YunServer|IPAddress|GSMClient|GSMModem|Keyboard|Ethernet|Console|GSMBand|Esplora|Stepper|Process|WiFiUDP|GSM_SMS|Mailbox|USBHost|Firmata|PImage|Client|Server|GSMPIN|FileIO|Bridge|Serial|EEPROM|Stream|Mouse|Audio|Servo|File|Task|GPRS|WiFi|Wire|TFT|GSM|SPI|SD)\b">
<token type="NameClass"/>
<rule
pattern="(Keyboard|KeyboardController|MouseController|SoftwareSerial|EthernetServer|EthernetClient|LiquidCrystal|RobotControl|GSMVoiceCall|EthernetUDP|EsploraTFT|HttpClient|RobotMotor|WiFiClient|GSMScanner|FileSystem|Scheduler|GSMServer|YunClient|YunServer|IPAddress|GSMClient|GSMModem|Keyboard|Ethernet|Console|GSMBand|Esplora|Stepper|Process|WiFiUDP|GSM_SMS|Mailbox|USBHost|Firmata|PImage|Client|Server|GSMPIN|FileIO|Bridge|Serial|EEPROM|Stream|Mouse|Audio|Servo|File|Task|GPRS|WiFi|Wire|TFT|GSM|SPI|SD)\b"
>
<token type="NameClass" />
</rule>
<rule pattern="(abs|Abs|accept|ACos|acos|acosf|addParameter|analogRead|AnalogRead|analogReadResolution|AnalogReadResolution|analogReference|AnalogReference|analogWrite|AnalogWrite|analogWriteResolution|AnalogWriteResolution|answerCall|asin|ASin|asinf|atan|ATan|atan2|ATan2|atan2f|atanf|attach|attached|attachGPRS|attachInterrupt|AttachInterrupt|autoscroll|available|availableForWrite|background|beep|begin|beginPacket|beginSD|beginSMS|beginSpeaker|beginTFT|beginTransmission|beginWrite|bit|Bit|BitClear|bitClear|bitRead|BitRead|bitSet|BitSet|BitWrite|bitWrite|blink|blinkVersion|BSSID|buffer|byte|cbrt|cbrtf|Ceil|ceil|ceilf|changePIN|char|charAt|checkPIN|checkPUK|checkReg|circle|cityNameRead|cityNameWrite|clear|clearScreen|click|close|compareTo|compassRead|concat|config|connect|connected|constrain|Constrain|copysign|copysignf|cos|Cos|cosf|cosh|coshf|countryNameRead|countryNameWrite|createChar|cursor|debugPrint|degrees|Delay|delay|DelayMicroseconds|delayMicroseconds|detach|DetachInterrupt|detachInterrupt|DigitalPinToInterrupt|digitalPinToInterrupt|DigitalRead|digitalRead|DigitalWrite|digitalWrite|disconnect|display|displayLogos|drawBMP|drawCompass|encryptionType|end|endPacket|endSMS|endsWith|endTransmission|endWrite|equals|equalsIgnoreCase|exists|exitValue|Exp|exp|expf|fabs|fabsf|fdim|fdimf|fill|find|findUntil|float|floor|Floor|floorf|flush|fma|fmaf|fmax|fmaxf|fmin|fminf|fmod|fmodf|gatewayIP|get|getAsynchronously|getBand|getButton|getBytes|getCurrentCarrier|getIMEI|getKey|getModifiers|getOemKey|getPINUsed|getResult|getSignalStrength|getSocket|getVoiceCallStatus|getXChange|getYChange|hangCall|height|highByte|HighByte|home|hypot|hypotf|image|indexOf|int|interrupts|IPAddress|IRread|isActionDone|isAlpha|isAlphaNumeric|isAscii|isControl|isDigit|isDirectory|isfinite|isGraph|isHexadecimalDigit|isinf|isListening|isLowerCase|isnan|isPIN|isPressed|isPrintable|isPunct|isSpace|isUpperCase|isValid|isWhitespace|keyboardRead|keyPressed|keyReleased|knobRead|lastIndexOf|ldexp|ldexpf|leftToRight|length|line|lineFollowConfig|listen|listenOnLocalhost|loadImage|localIP|log|Log|log10|log10f|logf|long|lowByte|LowByte|lrint|lrintf|lround|lroundf|macAddress|maintain|map|Map|Max|max|messageAvailable|Micros|micros|millis|Millis|Min|min|mkdir|motorsStop|motorsWrite|mouseDragged|mouseMoved|mousePressed|mouseReleased|move|noAutoscroll|noBlink|noBuffer|noCursor|noDisplay|noFill|noInterrupts|NoInterrupts|noListenOnLocalhost|noStroke|noTone|NoTone|onReceive|onRequest|open|openNextFile|overflow|parseCommand|parseFloat|parseInt|parsePacket|pauseMode|peek|PinMode|pinMode|playFile|playMelody|point|pointTo|position|Pow|pow|powf|prepare|press|print|printFirmwareVersion|println|printVersion|process|processInput|PulseIn|pulseIn|pulseInLong|PulseInLong|put|radians|random|Random|randomSeed|RandomSeed|read|readAccelerometer|readBlue|readButton|readBytes|readBytesUntil|readGreen|readJoystickButton|readJoystickSwitch|readJoystickX|readJoystickY|readLightSensor|readMessage|readMicrophone|readNetworks|readRed|readSlider|readString|readStringUntil|readTemperature|ready|rect|release|releaseAll|remoteIP|remoteNumber|remotePort|remove|replace|requestFrom|retrieveCallingNumber|rewindDirectory|rightToLeft|rmdir|robotNameRead|robotNameWrite|round|roundf|RSSI|run|runAsynchronously|running|runShellCommand|runShellCommandAsynchronously|scanNetworks|scrollDisplayLeft|scrollDisplayRight|seek|sendAnalog|sendDigitalPortPair|sendDigitalPorts|sendString|sendSysex|Serial_Available|Serial_Begin|Serial_End|Serial_Flush|Serial_Peek|Serial_Print|Serial_Println|Serial_Read|serialEvent|setBand|setBitOrder|setCharAt|setClockDivider|setCursor|setDataMode|setDNS|setFirmwareVersion|setMode|setPINUsed|setSpeed|setTextSize|setTimeout|ShiftIn|shiftIn|ShiftOut|shiftOut|shutdown|signbit|sin|Sin|sinf|sinh|sinhf|size|sizeof|Sq|sq|Sqrt|sqrt|sqrtf|SSID|startLoop|startsWith|step|stop|stroke|subnetMask|substring|switchPIN|tan|Tan|tanf|tanh|tanhf|tempoWrite|text|toCharArray|toInt|toLowerCase|tone|Tone|toUpperCase|transfer|trim|trunc|truncf|tuneWrite|turn|updateIR|userNameRead|userNameWrite|voiceCall|waitContinue|width|WiFiServer|word|write|writeBlue|writeGreen|writeJSON|writeMessage|writeMicroseconds|writeRed|writeRGB|yield|Yield)\b">
<token type="NameFunction"/>
<rule
pattern="(abs|Abs|accept|ACos|acos|acosf|addParameter|analogRead|AnalogRead|analogReadResolution|AnalogReadResolution|analogReference|AnalogReference|analogWrite|AnalogWrite|analogWriteResolution|AnalogWriteResolution|answerCall|asin|ASin|asinf|atan|ATan|atan2|ATan2|atan2f|atanf|attach|attached|attachGPRS|attachInterrupt|AttachInterrupt|autoscroll|available|availableForWrite|background|beep|begin|beginPacket|beginSD|beginSMS|beginSpeaker|beginTFT|beginTransmission|beginWrite|bit|Bit|BitClear|bitClear|bitRead|BitRead|bitSet|BitSet|BitWrite|bitWrite|blink|blinkVersion|BSSID|buffer|byte|cbrt|cbrtf|Ceil|ceil|ceilf|changePIN|char|charAt|checkPIN|checkPUK|checkReg|circle|cityNameRead|cityNameWrite|clear|clearScreen|click|close|compareTo|compassRead|concat|config|connect|connected|constrain|Constrain|copysign|copysignf|cos|Cos|cosf|cosh|coshf|countryNameRead|countryNameWrite|createChar|cursor|debugPrint|degrees|Delay|delay|DelayMicroseconds|delayMicroseconds|detach|DetachInterrupt|detachInterrupt|DigitalPinToInterrupt|digitalPinToInterrupt|DigitalRead|digitalRead|DigitalWrite|digitalWrite|disconnect|display|displayLogos|drawBMP|drawCompass|encryptionType|end|endPacket|endSMS|endsWith|endTransmission|endWrite|equals|equalsIgnoreCase|exists|exitValue|Exp|exp|expf|fabs|fabsf|fdim|fdimf|fill|find|findUntil|float|floor|Floor|floorf|flush|fma|fmaf|fmax|fmaxf|fmin|fminf|fmod|fmodf|gatewayIP|get|getAsynchronously|getBand|getButton|getBytes|getCurrentCarrier|getIMEI|getKey|getModifiers|getOemKey|getPINUsed|getResult|getSignalStrength|getSocket|getVoiceCallStatus|getXChange|getYChange|hangCall|height|highByte|HighByte|home|hypot|hypotf|image|indexOf|int|interrupts|IPAddress|IRread|isActionDone|isAlpha|isAlphaNumeric|isAscii|isControl|isDigit|isDirectory|isfinite|isGraph|isHexadecimalDigit|isinf|isListening|isLowerCase|isnan|isPIN|isPressed|isPrintable|isPunct|isSpace|isUpperCase|isValid|isWhitespace|keyboardRead|keyPressed|keyReleased|knobRead|lastIndexOf|ldexp|ldexpf|leftToRight|length|line|lineFollowConfig|listen|listenOnLocalhost|loadImage|localIP|log|Log|log10|log10f|logf|long|lowByte|LowByte|lrint|lrintf|lround|lroundf|macAddress|maintain|map|Map|Max|max|messageAvailable|Micros|micros|millis|Millis|Min|min|mkdir|motorsStop|motorsWrite|mouseDragged|mouseMoved|mousePressed|mouseReleased|move|noAutoscroll|noBlink|noBuffer|noCursor|noDisplay|noFill|noInterrupts|NoInterrupts|noListenOnLocalhost|noStroke|noTone|NoTone|onReceive|onRequest|open|openNextFile|overflow|parseCommand|parseFloat|parseInt|parsePacket|pauseMode|peek|PinMode|pinMode|playFile|playMelody|point|pointTo|position|Pow|pow|powf|prepare|press|print|printFirmwareVersion|println|printVersion|process|processInput|PulseIn|pulseIn|pulseInLong|PulseInLong|put|radians|random|Random|randomSeed|RandomSeed|read|readAccelerometer|readBlue|readButton|readBytes|readBytesUntil|readGreen|readJoystickButton|readJoystickSwitch|readJoystickX|readJoystickY|readLightSensor|readMessage|readMicrophone|readNetworks|readRed|readSlider|readString|readStringUntil|readTemperature|ready|rect|release|releaseAll|remoteIP|remoteNumber|remotePort|remove|replace|requestFrom|retrieveCallingNumber|rewindDirectory|rightToLeft|rmdir|robotNameRead|robotNameWrite|round|roundf|RSSI|run|runAsynchronously|running|runShellCommand|runShellCommandAsynchronously|scanNetworks|scrollDisplayLeft|scrollDisplayRight|seek|sendAnalog|sendDigitalPortPair|sendDigitalPorts|sendString|sendSysex|Serial_Available|Serial_Begin|Serial_End|Serial_Flush|Serial_Peek|Serial_Print|Serial_Println|Serial_Read|serialEvent|setBand|setBitOrder|setCharAt|setClockDivider|setCursor|setDataMode|setDNS|setFirmwareVersion|setMode|setPINUsed|setSpeed|setTextSize|setTimeout|ShiftIn|shiftIn|ShiftOut|shiftOut|shutdown|signbit|sin|Sin|sinf|sinh|sinhf|size|sizeof|Sq|sq|Sqrt|sqrt|sqrtf|SSID|startLoop|startsWith|step|stop|stroke|subnetMask|substring|switchPIN|tan|Tan|tanf|tanh|tanhf|tempoWrite|text|toCharArray|toInt|toLowerCase|tone|Tone|toUpperCase|transfer|trim|trunc|truncf|tuneWrite|turn|updateIR|userNameRead|userNameWrite|voiceCall|waitContinue|width|WiFiServer|word|write|writeBlue|writeGreen|writeJSON|writeMessage|writeMicroseconds|writeRed|writeRGB|yield|Yield)\b"
>
<token type="NameFunction" />
</rule>
<rule pattern="(typename|__inline|restrict|_inline|thread|inline|naked)\b">
<token type="KeywordReserved"/>
<token type="KeywordReserved" />
</rule>
<rule pattern="(__m(128i|128d|128|64))\b">
<token type="KeywordReserved"/>
<token type="KeywordReserved" />
</rule>
<rule pattern="__(forceinline|identifier|unaligned|declspec|fastcall|finally|stdcall|wchar_t|assume|except|int32|cdecl|int16|leave|based|raise|int64|noop|int8|w64|try|asm)\b">
<token type="KeywordReserved"/>
<rule
pattern="__(forceinline|identifier|unaligned|declspec|fastcall|finally|stdcall|wchar_t|assume|except|int32|cdecl|int16|leave|based|raise|int64|noop|int8|w64|try|asm)\b"
>
<token type="KeywordReserved" />
</rule>
<rule pattern="(true|false|NULL)\b">
<token type="NameBuiltin"/>
<token type="NameBuiltin" />
</rule>
<rule pattern="([a-zA-Z_]\w*)(\s*)(:)(?!:)">
<bygroups>
<token type="NameLabel"/>
<token type="Text"/>
<token type="Punctuation"/>
<token type="NameLabel" />
<token type="Text" />
<token type="Punctuation" />
</bygroups>
</rule>
<rule pattern="[a-zA-Z_]\w*">
<token type="Name"/>
<token type="Name" />
</rule>
</state>
<state name="function">
<rule>
<include state="whitespace"/>
<include state="whitespace" />
</rule>
<rule>
<include state="statements"/>
<include state="statements" />
</rule>
<rule pattern=";">
<token type="Punctuation"/>
<token type="Punctuation" />
</rule>
<rule pattern="\{">
<token type="Punctuation"/>
<push/>
<token type="Punctuation" />
<push />
</rule>
<rule pattern="\}">
<token type="Punctuation"/>
<pop depth="1"/>
<token type="Punctuation" />
<pop depth="1" />
</rule>
</state>
<state name="if0">
<rule pattern="^\s*#if.*?(?&lt;!\\)\n">
<token type="CommentPreproc"/>
<push/>
<token type="CommentPreproc" />
<push />
</rule>
<rule pattern="^\s*#el(?:se|if).*\n">
<token type="CommentPreproc"/>
<pop depth="1"/>
<token type="CommentPreproc" />
<pop depth="1" />
</rule>
<rule pattern="^\s*#endif.*?(?&lt;!\\)\n">
<token type="CommentPreproc"/>
<pop depth="1"/>
<token type="CommentPreproc" />
<pop depth="1" />
</rule>
<rule pattern=".*?\n">
<token type="Comment"/>
<token type="Comment" />
</rule>
</state>
<state name="classname">
<rule pattern="[a-zA-Z_]\w*">
<token type="NameClass"/>
<pop depth="1"/>
<token type="NameClass" />
<pop depth="1" />
</rule>
<rule pattern="\s*(?=&gt;)">
<token type="Text"/>
<pop depth="1"/>
<token type="Text" />
<pop depth="1" />
</rule>
</state>
<state name="statement">
<rule>
<include state="whitespace"/>
<include state="whitespace" />
</rule>
<rule>
<include state="statements"/>
<include state="statements" />
</rule>
<rule pattern="[{}]">
<token type="Punctuation"/>
<token type="Punctuation" />
</rule>
<rule pattern=";">
<token type="Punctuation"/>
<pop depth="1"/>
<token type="Punctuation" />
<pop depth="1" />
</rule>
</state>
<state name="root">
<rule>
<include state="whitespace"/>
<include state="whitespace" />
</rule>
<rule pattern="((?:[\w*\s])+?(?:\s|[*]))([a-zA-Z_]\w*)(\s*\([^;]*?\))([^;{]*)(\{)">
<bygroups>
<usingself state="root"/>
<token type="NameFunction"/>
<usingself state="root"/>
<usingself state="root"/>
<token type="Punctuation"/>
<usingself state="root" />
<token type="NameFunction" />
<usingself state="root" />
<usingself state="root" />
<token type="Punctuation" />
</bygroups>
<push state="function"/>
<push state="function" />
</rule>
<rule pattern="((?:[\w*\s])+?(?:\s|[*]))([a-zA-Z_]\w*)(\s*\([^;]*?\))([^;]*)(;)">
<bygroups>
<usingself state="root"/>
<token type="NameFunction"/>
<usingself state="root"/>
<usingself state="root"/>
<token type="Punctuation"/>
<usingself state="root" />
<token type="NameFunction" />
<usingself state="root" />
<usingself state="root" />
<token type="Punctuation" />
</bygroups>
</rule>
<rule>
<push state="statement"/>
<push state="statement" />
</rule>
<rule pattern="__(multiple_inheritance|virtual_inheritance|single_inheritance|interface|uuidof|super|event)\b">
<token type="KeywordReserved"/>
<token type="KeywordReserved" />
</rule>
<rule pattern="__(offload|blockingoffload|outer)\b">
<token type="KeywordPseudo"/>
<token type="KeywordPseudo" />
</rule>
</state>
</rules>
</lexer>
</lexer>
+47 -47
View File
@@ -11,116 +11,116 @@
<rules>
<state name="root">
<rule>
<include state="commentsandwhitespace"/>
<include state="commentsandwhitespace" />
</rule>
<rule pattern="(\.\w+)([ \t]+\w+\s+?)?">
<bygroups>
<token type="KeywordNamespace"/>
<token type="NameLabel"/>
<token type="KeywordNamespace" />
<token type="NameLabel" />
</bygroups>
</rule>
<rule pattern="(\w+)(:)(\s+\.\w+\s+)">
<bygroups>
<token type="NameLabel"/>
<token type="Punctuation"/>
<token type="KeywordNamespace"/>
<token type="NameLabel" />
<token type="Punctuation" />
<token type="KeywordNamespace" />
</bygroups>
<push state="literal"/>
<push state="literal" />
</rule>
<rule pattern="(\w+)(:)">
<bygroups>
<token type="NameLabel"/>
<token type="Punctuation"/>
<token type="NameLabel" />
<token type="Punctuation" />
</bygroups>
</rule>
<rule pattern="svc\s+\w+">
<token type="NameNamespace"/>
<token type="NameNamespace" />
</rule>
<rule pattern="[a-zA-Z]+">
<token type="Text"/>
<push state="opcode"/>
<token type="Text" />
<push state="opcode" />
</rule>
</state>
<state name="commentsandwhitespace">
<rule pattern="\s+">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="[@;].*?\n">
<token type="CommentSingle"/>
<token type="CommentSingle" />
</rule>
<rule pattern="/\*.*?\*/">
<token type="CommentMultiline"/>
<token type="CommentMultiline" />
</rule>
</state>
<state name="literal">
<rule pattern="0b[01]+">
<token type="LiteralNumberBin"/>
<pop depth="1"/>
<token type="LiteralNumberBin" />
<pop depth="1" />
</rule>
<rule pattern="0x\w{1,8}">
<token type="LiteralNumberHex"/>
<pop depth="1"/>
<token type="LiteralNumberHex" />
<pop depth="1" />
</rule>
<rule pattern="0\d+">
<token type="LiteralNumberOct"/>
<pop depth="1"/>
<token type="LiteralNumberOct" />
<pop depth="1" />
</rule>
<rule pattern="\d+?\.\d+?">
<token type="LiteralNumberFloat"/>
<pop depth="1"/>
<token type="LiteralNumberFloat" />
<pop depth="1" />
</rule>
<rule pattern="\d+">
<token type="LiteralNumberInteger"/>
<pop depth="1"/>
<token type="LiteralNumberInteger" />
<pop depth="1" />
</rule>
<rule pattern="(&#34;)(.+)(&#34;)">
<bygroups>
<token type="Punctuation"/>
<token type="LiteralStringDouble"/>
<token type="Punctuation"/>
<token type="Punctuation" />
<token type="LiteralStringDouble" />
<token type="Punctuation" />
</bygroups>
<pop depth="1"/>
<pop depth="1" />
</rule>
<rule pattern="(&#39;)(.{1}|\\.{1})(&#39;)">
<bygroups>
<token type="Punctuation"/>
<token type="LiteralStringChar"/>
<token type="Punctuation"/>
<token type="Punctuation" />
<token type="LiteralStringChar" />
<token type="Punctuation" />
</bygroups>
<pop depth="1"/>
<pop depth="1" />
</rule>
</state>
<state name="opcode">
<rule pattern="\n">
<token type="Text"/>
<pop depth="1"/>
<token type="Text" />
<pop depth="1" />
</rule>
<rule pattern="(@|;).*\n">
<token type="CommentSingle"/>
<pop depth="1"/>
<token type="CommentSingle" />
<pop depth="1" />
</rule>
<rule pattern="(\s+|,)">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="[rapcfxwbhsdqv]\d{1,2}">
<token type="NameClass"/>
<token type="NameClass" />
</rule>
<rule pattern="=0x\w+">
<rule pattern="(=)(0x\w+)">
<bygroups>
<token type="Text"/>
<token type="NameLabel"/>
<token type="Text" />
<token type="NameLabel" />
</bygroups>
</rule>
<rule pattern="(=)(\w+)">
<bygroups>
<token type="Text"/>
<token type="NameLabel"/>
<token type="Text" />
<token type="NameLabel" />
</bygroups>
</rule>
<rule pattern="#">
<token type="Text"/>
<push state="literal"/>
<token type="Text" />
<push state="literal" />
</rule>
</state>
</rules>
</lexer>
</lexer>
@@ -0,0 +1,79 @@
<lexer>
<config>
<name>Core</name>
<alias>core</alias>
<filename>*.core</filename>
<mime_type>text/x-core</mime_type>
</config>
<rules>
<state name="root">
<rule pattern="\s+">
<token type="TextWhitespace"/>
</rule>
<rule pattern="//(.*?)\n">
<token type="CommentSingle"/>
</rule>
<rule pattern="(const|class|value|union|enum|trait|impl|annotation)\b">
<token type="KeywordDeclaration"/>
</rule>
<rule pattern="(fun|let|var)\b">
<token type="KeywordDeclaration"/>
</rule>
<rule pattern="(mod|use)\b">
<token type="KeywordNamespace"/>
</rule>
<rule pattern="(if|else|is|for|in|while|return)\b">
<token type="Keyword"/>
</rule>
<rule pattern="(true|false|self)\b">
<token type="KeywordConstant"/>
</rule>
<rule pattern="0[b][01](_?[01])*(i32|i64|u8|f32|f64)?">
<token type="LiteralNumberBin"/>
</rule>
<rule pattern="0[x][\da-fA-F](_?[\dA-Fa-f])*(i32|i64|u8|f32|f64)?">
<token type="LiteralNumberHex"/>
</rule>
<rule pattern="\d(_?\d)*\.\d(_?\d)*([eE][-+]?\d(_?\d)*)?(f32|f64)?">
<token type="LiteralNumberFloat"/>
</rule>
<rule pattern="\d(_?\d)*(i32|i64|u8|f32|f64)?">
<token type="LiteralNumberInteger"/>
</rule>
<rule pattern="&#34;">
<token type="LiteralString"/>
<push state="string"/>
</rule>
<rule pattern="@([a-z_]\w*[!?]?)">
<token type="NameAttribute"/>
</rule>
<rule pattern="===|!==|==|!=|&gt;=|&lt;=|[&gt;&lt;*/+-=&amp;|^]">
<token type="Operator"/>
</rule>
<rule pattern="[A-Z][A-Za-z0-9_]*">
<token type="NameClass"/>
</rule>
<rule pattern="([a-z_]\w*[!?]?)">
<token type="Name"/>
</rule>
<rule pattern="[(){}\[\],.;]">
<token type="Punctuation"/>
</rule>
</state>
<state name="string">
<rule pattern="&#34;">
<token type="LiteralString"/>
<pop depth="1"/>
</rule>
<rule pattern="\\[&#34;\\fnrt]|\\u\{[\da-fA-F]{1,6}\}">
<token type="LiteralStringEscape"/>
</rule>
<rule pattern="[^\\&#34;]+">
<token type="LiteralString"/>
</rule>
<rule pattern="\\">
<token type="LiteralString"/>
</rule>
</state>
</rules>
</lexer>
File diff suppressed because one or more lines are too long
+28 -17
View File
@@ -3,55 +3,66 @@
<name>Docker</name>
<alias>docker</alias>
<alias>dockerfile</alias>
<alias>containerfile</alias>
<filename>Dockerfile</filename>
<filename>Dockerfile.*</filename>
<filename>*.Dockerfile</filename>
<filename>*.docker</filename>
<filename>Containerfile</filename>
<filename>Containerfile.*</filename>
<filename>*.Containerfile</filename>
<mime_type>text/x-dockerfile-config</mime_type>
<case_insensitive>true</case_insensitive>
</config>
<rules>
<state name="root">
<rule pattern="#.*">
<token type="Comment"/>
<token type="Comment" />
</rule>
<rule pattern="(ONBUILD)((?:\s*\\?\s*))">
<bygroups>
<token type="Keyword"/>
<using lexer="Bash"/>
<token type="Keyword" />
<using lexer="Bash" />
</bygroups>
</rule>
<rule pattern="(HEALTHCHECK)(((?:\s*\\?\s*)--\w+=\w+(?:\s*\\?\s*))*)">
<rule pattern="(HEALTHCHECK)((?:(?:\s*\\?\s*)--\w+=\w+(?:\s*\\?\s*))*)">
<bygroups>
<token type="Keyword"/>
<using lexer="Bash"/>
<token type="Keyword" />
<using lexer="Bash" />
</bygroups>
</rule>
<rule pattern="(VOLUME|ENTRYPOINT|CMD|SHELL)((?:\s*\\?\s*))(\[.*?\])">
<bygroups>
<token type="Keyword"/>
<using lexer="Bash"/>
<using lexer="JSON"/>
<token type="Keyword" />
<using lexer="Bash" />
<using lexer="JSON" />
</bygroups>
</rule>
<rule pattern="(LABEL|ENV|ARG)((?:(?:\s*\\?\s*)\w+=\w+(?:\s*\\?\s*))*)">
<bygroups>
<token type="Keyword"/>
<using lexer="Bash"/>
<token type="Keyword" />
<using lexer="Bash" />
</bygroups>
</rule>
<rule pattern="((?:FROM|MAINTAINER|EXPOSE|WORKDIR|USER|STOPSIGNAL)|VOLUME)\b(.*)">
<rule
pattern="((?:FROM|MAINTAINER|EXPOSE|WORKDIR|USER|STOPSIGNAL)|VOLUME)\b(\s)([\S]*)\b(?:(\s)(AS)\b(\s)([\S]*))?\b"
>
<bygroups>
<token type="Keyword"/>
<token type="LiteralString"/>
<token type="Keyword" />
<token type="TextWhitespace" />
<token type="LiteralString" />
<token type="TextWhitespace" />
<token type="Keyword" />
<token type="TextWhitespace" />
<token type="LiteralString" />
</bygroups>
</rule>
<rule pattern="((?:RUN|CMD|ENTRYPOINT|ENV|ARG|LABEL|ADD|COPY))">
<token type="Keyword"/>
<token type="Keyword" />
</rule>
<rule pattern="(.*\\\n)*.+">
<using lexer="Bash"/>
<using lexer="Bash" />
</rule>
</state>
</rules>
</lexer>
</lexer>
+5 -22
View File
@@ -33,7 +33,6 @@
</rule>
<rule pattern="(type)\b">
<token type="Keyword"/>
<push state="typename"/>
</rule>
<rule pattern="(True|False)\b">
<token type="KeywordConstant"/>
@@ -63,12 +62,11 @@
<rule pattern="[{}()\[\],]|[#(]|\.\.|&lt;&gt;|&lt;&lt;|&gt;&gt;">
<token type="Punctuation"/>
</rule>
<rule pattern="[+\-*/%!=&lt;&gt;&amp;|.]|&lt;-">
<token type="Operator"/>
</rule>
<rule pattern=":|-&gt;">
<token type="Operator"/>
<push state="typename"/>
</rule>
<rule pattern="[+\-*/%!=&lt;&gt;&amp;|.]|&lt;-">
<token type="Operator"/>
</rule>
<rule pattern="([a-z_][A-Za-z0-9_]*)(\()">
<bygroups>
@@ -76,28 +74,13 @@
<token type="Punctuation"/>
</bygroups>
</rule>
<rule pattern="([A-Z][A-Za-z0-9_]*)(\()">
<bygroups>
<token type="NameClass"/>
<token type="Punctuation"/>
</bygroups>
<rule pattern="[A-Z][A-Za-z0-9_]*">
<token type="NameClass"/>
</rule>
<rule pattern="([a-z_]\w*[!?]?)">
<token type="Name"/>
</rule>
</state>
<state name="typename">
<rule pattern="\s+">
<token type="TextWhitespace"/>
</rule>
<rule pattern="[A-Z][A-Za-z0-9_]*">
<token type="NameClass"/>
<pop depth="1"/>
</rule>
<rule>
<pop depth="1"/>
</rule>
</state>
<state name="string">
<rule pattern="&#34;">
<token type="LiteralString"/>
+44 -62
View File
@@ -7,143 +7,125 @@
<rules>
<state name="root">
<rule pattern="(#.*)">
<bygroups>
<token type="CommentSingle"/>
</bygroups>
<token type="CommentSingle" />
</rule>
<rule pattern="((\b(0(b|B|o|O|x|X)[a-fA-F0-9]+)\b)|(\b(0|[1-9][0-9]*)\b))">
<bygroups>
<token type="LiteralNumber"/>
</bygroups>
<token type="LiteralNumber" />
</rule>
<rule pattern="((\b(true|false)\b))">
<bygroups>
<token type="NameBuiltin"/>
</bygroups>
<token type="NameBuiltin" />
</rule>
<rule pattern="(\bstring\b|\bint\b|\bbool\b|\bfs\b|\boption\b)">
<bygroups>
<token type="KeywordType"/>
</bygroups>
<token type="KeywordType" />
</rule>
<rule pattern="(\b[a-zA-Z_][a-zA-Z0-9]*\b)(\()">
<bygroups>
<token type="NameFunction"/>
<token type="Punctuation"/>
<token type="NameFunction" />
<token type="Punctuation" />
</bygroups>
<push state="params"/>
<push state="params" />
</rule>
<rule pattern="(\{)">
<bygroups>
<token type="Punctuation"/>
</bygroups>
<push state="block"/>
<token type="Punctuation" />
<push state="block" />
</rule>
<rule pattern="(\n|\r|\r\n)">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern=".">
<token type="Text"/>
<token type="Text" />
</rule>
</state>
<state name="string">
<rule pattern="&#34;">
<token type="LiteralString"/>
<pop depth="1"/>
<token type="LiteralString" />
<pop depth="1" />
</rule>
<rule pattern="\\&#34;">
<token type="LiteralString"/>
<token type="LiteralString" />
</rule>
<rule pattern="[^\\&#34;]+">
<token type="LiteralString"/>
<token type="LiteralString" />
</rule>
</state>
<state name="block">
<rule pattern="(\})">
<bygroups>
<token type="Punctuation"/>
</bygroups>
<pop depth="1"/>
<token type="Punctuation" />
<pop depth="1" />
</rule>
<rule pattern="(#.*)">
<bygroups>
<token type="CommentSingle"/>
</bygroups>
<token type="CommentSingle" />
</rule>
<rule pattern="((\b(0(b|B|o|O|x|X)[a-fA-F0-9]+)\b)|(\b(0|[1-9][0-9]*)\b))">
<bygroups>
<token type="LiteralNumber"/>
</bygroups>
<token type="LiteralNumber" />
</rule>
<rule pattern="((\b(true|false)\b))">
<bygroups>
<token type="KeywordConstant"/>
</bygroups>
<token type="KeywordConstant" />
</rule>
<rule pattern="&#34;">
<token type="LiteralString"/>
<push state="string"/>
<token type="LiteralString" />
<push state="string" />
</rule>
<rule pattern="(with)">
<bygroups>
<token type="KeywordReserved"/>
</bygroups>
<token type="KeywordReserved" />
</rule>
<rule pattern="(as)([\t ]+)(\b[a-zA-Z_][a-zA-Z0-9]*\b)">
<bygroups>
<token type="KeywordReserved"/>
<token type="Text"/>
<token type="NameFunction"/>
<token type="KeywordReserved" />
<token type="Text" />
<token type="NameFunction" />
</bygroups>
</rule>
<rule pattern="(\bstring\b|\bint\b|\bbool\b|\bfs\b|\boption\b)([\t ]+)(\{)">
<bygroups>
<token type="KeywordType"/>
<token type="Text"/>
<token type="Punctuation"/>
<token type="KeywordType" />
<token type="Text" />
<token type="Punctuation" />
</bygroups>
<push state="block"/>
<push state="block" />
</rule>
<rule pattern="(?!\b(?:scratch|image|resolve|http|checksum|chmod|filename|git|keepGitDir|local|includePatterns|excludePatterns|followPaths|generate|frontendInput|shell|run|readonlyRootfs|env|dir|user|network|security|host|ssh|secret|mount|target|localPath|uid|gid|mode|readonly|tmpfs|sourcePath|cache|mkdir|createParents|chown|createdTime|mkfile|rm|allowNotFound|allowWildcards|copy|followSymlinks|contentsOnly|unpack|createDestPath)\b)(\b[a-zA-Z_][a-zA-Z0-9]*\b)">
<rule
pattern="(?!\b(?:scratch|image|resolve|http|checksum|chmod|filename|git|keepGitDir|local|includePatterns|excludePatterns|followPaths|generate|frontendInput|shell|run|readonlyRootfs|env|dir|user|network|security|host|ssh|secret|mount|target|localPath|uid|gid|mode|readonly|tmpfs|sourcePath|cache|mkdir|createParents|chown|createdTime|mkfile|rm|allowNotFound|allowWildcards|copy|followSymlinks|contentsOnly|unpack|createDestPath)\b)(\b[a-zA-Z_][a-zA-Z0-9]*\b)"
>
<bygroups>
<token type="NameOther"/>
<token type="NameOther" />
</bygroups>
</rule>
<rule pattern="(\n|\r|\r\n)">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern=".">
<token type="Text"/>
<token type="Text" />
</rule>
</state>
<state name="params">
<rule pattern="(\))">
<bygroups>
<token type="Punctuation"/>
<token type="Punctuation" />
</bygroups>
<pop depth="1"/>
<pop depth="1" />
</rule>
<rule pattern="(variadic)">
<bygroups>
<token type="Keyword"/>
<token type="Keyword" />
</bygroups>
</rule>
<rule pattern="(\bstring\b|\bint\b|\bbool\b|\bfs\b|\boption\b)">
<bygroups>
<token type="KeywordType"/>
<token type="KeywordType" />
</bygroups>
</rule>
<rule pattern="(\b[a-zA-Z_][a-zA-Z0-9]*\b)">
<bygroups>
<token type="NameOther"/>
<token type="NameOther" />
</bygroups>
</rule>
<rule pattern="(\n|\r|\r\n)">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern=".">
<token type="Text"/>
<token type="Text" />
</rule>
</state>
</rules>
</lexer>
</lexer>
File diff suppressed because one or more lines are too long
@@ -3,6 +3,7 @@
<name>Kotlin</name>
<alias>kotlin</alias>
<filename>*.kt</filename>
<filename>*.kts</filename>
<mime_type>text/x-kotlin</mime_type>
<dot_all>true</dot_all>
</config>
@@ -0,0 +1,56 @@
<lexer>
<config>
<name>Lean4</name>
<alias>lean4</alias>
<alias>lean</alias>
<filename>*.lean</filename>
<mime_type>text/x-lean4</mime_type>
<mime_type>text/x-lean</mime_type>
</config>
<rules>
<state name="expression">
<rule pattern="\s+"><token type="TextWhitespace"/></rule>
<rule pattern="/--"><token type="LiteralStringDoc"/><push state="docstring"/></rule>
<rule pattern="/-"><token type="Comment"/><push state="comment"/></rule>
<rule pattern="--.*$"><token type="CommentSingle"/></rule>
<rule pattern="\b(Type|Prop|Sort)\b"><token type="KeywordType"/></rule>
<rule pattern="\b(sorry|admit)\b"><token type="GenericError"/></rule>
<rule pattern="(!=|\#|\&amp;|\&amp;\&amp;|\*|\+|\-|/|@|!|\-\.|\-&gt;|\.|\.\.|\.\.\.|::|:&gt;|;|;;|&lt;|&lt;\-|=|==|&gt;|_|\||\|\||\~|=&gt;|&lt;=|&gt;=|/\\|\\/|∀|Π|λ|↔|∧||≠|≤|≥|¬|⁻¹|⬝|▸|→|∃|≈|×|⌞|⌟|≡|⟨|⟩|↦)"><token type="NameBuiltinPseudo"/></rule>
<rule pattern="(\(|\)|:|\{|\}|\[|\]|⦃|⦄|:=|,)"><token type="Operator"/></rule>
<rule pattern="(?![λΠΣ])[_a-zA-Zα-ωΑ-Ωϊ-ϻἀ-῾℀-⅏𝒜-𝖟](?:(?![λΠΣ])[_a-zA-Zα-ωΑ-Ωϊ-ϻἀ-῾℀-⅏𝒜-𝖟0-9&#x27;ⁿ-₉ₐ-ₜᵢ-ᵪ!?])*"><token type="Name"/></rule>
<rule pattern="``?(?![λΠΣ])[_a-zA-Zα-ωΑ-Ωϊ-ϻἀ-῾℀-⅏𝒜-𝖟](?:(?![λΠΣ])[_a-zA-Zα-ωΑ-Ωϊ-ϻἀ-῾℀-⅏𝒜-𝖟0-9&#x27;ⁿ-₉ₐ-ₜᵢ-ᵪ!?])*(\.(?![λΠΣ])[_a-zA-Zα-ωΑ-Ωϊ-ϻἀ-῾℀-⅏𝒜-𝖟](?:(?![λΠΣ])[_a-zA-Zα-ωΑ-Ωϊ-ϻἀ-῾℀-⅏𝒜-𝖟0-9&#x27;ⁿ-₉ₐ-ₜᵢ-ᵪ!?])*)*"><token type="LiteralStringSymbol"/></rule>
<rule pattern="(?&lt;=\.)\d+"><token type="LiteralNumber"/></rule>
<rule pattern="(\d+\.\d*)([eE][+-]?[0-9]+)?"><token type="LiteralNumberFloat"/></rule>
<rule pattern="\d+"><token type="LiteralNumberInteger"/></rule>
<rule pattern="&quot;"><token type="LiteralStringDouble"/><push state="string"/></rule>
<rule pattern="[~?][a-z][\w\&#x27;]*:"><token type="NameVariable"/></rule>
<rule pattern="\S"><token type="NameBuiltinPseudo"/></rule>
</state>
<state name="root">
<rule pattern="\b(import|unif_hint|renaming|inline|hiding|lemma|variable|theorem|axiom|inductive|structure|universe|alias|\#help|precedence|postfix|prefix|infix|infixl|infixr|notation|\#eval|\#check|\#reduce|\#exit|end|private|using|namespace|instance|section|protected|export|set_option|extends|open|example|\#print|opaque|def|macro|elab|syntax|macro_rules|\#reduce|where|abbrev|noncomputable|class|attribute|\#synth|mutual|scoped|local)\b"><token type="KeywordNamespace"/></rule>
<rule pattern="\b(forall|fun|obtain|from|have|show|assume|let|if|else|then|by|in|with|calc|match|nomatch|do|at)\b"><token type="Keyword"/></rule>
<rule pattern="@\["><token type="KeywordDeclaration"/><push state="attribute"/></rule>
<rule><include state="expression"/></rule>
</state>
<state name="attribute">
<rule pattern="\]"><token type="KeywordDeclaration"/><pop depth="1"/></rule>
<rule><include state="expression"/></rule>
</state>
<state name="comment">
<rule pattern="[^/-]+"><token type="CommentMultiline"/></rule>
<rule pattern="/-"><token type="CommentMultiline"/><push/></rule>
<rule pattern="-/"><token type="CommentMultiline"/><pop depth="1"/></rule>
<rule pattern="[/-]"><token type="CommentMultiline"/></rule>
</state>
<state name="docstring">
<rule pattern="[^/-]+"><token type="LiteralStringDoc"/></rule>
<rule pattern="-/"><token type="LiteralStringDoc"/><pop depth="1"/></rule>
<rule pattern="[/-]"><token type="LiteralStringDoc"/></rule>
</state>
<state name="string">
<rule pattern="[^\\&quot;]+"><token type="LiteralStringDouble"/></rule>
<rule pattern="\\[n&quot;\\\n]"><token type="LiteralStringEscape"/></rule>
<rule pattern="&quot;"><token type="LiteralStringDouble"/><pop depth="1"/></rule>
</state>
</rules>
</lexer>
+83
View File
@@ -0,0 +1,83 @@
<lexer>
<config>
<name>lox</name>
<filename>*.lox</filename>
<dot_all>true</dot_all>
<ensure_nl>true</ensure_nl>
</config>
<rules>
<state name="classname">
<rule pattern="[a-zA-Z_]\w*">
<token type="NameClass"/>
<pop depth="1"/>
</rule>
</state>
<state name="funname">
<rule pattern="[a-zA-Z_]\w*">
<token type="NameFunction"/>
<pop depth="1"/>
</rule>
</state>
<state name="varname">
<rule pattern="[a-zA-Z_]\w*">
<token type="NameVariable"/>
<pop depth="1"/>
</rule>
</state>
<state name="whitespace">
<rule pattern="\n">
<token type="Text"/>
</rule>
<rule pattern="\s+">
<token type="Text"/>
</rule>
</state>
<state name="root">
<rule>
<include state="whitespace"/>
</rule>
<rule pattern="//.*?\n">
<token type="CommentSingle"/>
</rule>
<rule pattern="(and|else|for|if|or|print|return|super|this|while)\b">
<token type="Keyword"/>
</rule>
<rule pattern="(false|nil|true)\b">
<token type="KeywordConstant"/>
</rule>
<rule pattern="(class)(\s*)">
<token type="KeywordDeclaration"/>
<push state="classname"/>
</rule>
<rule pattern="(fun)(\s*)">
<token type="KeywordDeclaration"/>
<push state="funname"/>
</rule>
<rule pattern="(var)(\s*)">
<token type="KeywordDeclaration"/>
<push state="varname"/>
</rule>
<rule pattern="\d+(\.\d*|[eE][+\-]?\d+)">
<token type="LiteralNumberFloat"/>
</rule>
<rule pattern="[0-9][0-9]*">
<token type="LiteralNumberInteger"/>
</rule>
<rule pattern="&#34;(\\\\|\\&#34;|[^&#34;])*&#34;">
<token type="LiteralStringDouble"/>
</rule>
<rule pattern="!|\+|-|\*|/|&lt;|&gt;|=">
<token type="Operator"/>
</rule>
<rule pattern="[{(;,]">
<token type="Punctuation"/>
</rule>
<rule pattern="[}).]">
<token type="Punctuation"/>
</rule>
<rule pattern="[a-zA-Z_]\w*">
<token type="NameVariable"/>
</rule>
</state>
</rules>
</lexer>
@@ -2,8 +2,10 @@
<config>
<name>Lua</name>
<alias>lua</alias>
<alias>luau</alias>
<filename>*.lua</filename>
<filename>*.wlua</filename>
<filename>*.luau</filename>
<mime_type>text/x-lua</mime_type>
<mime_type>application/x-lua</mime_type>
</config>
+228
View File
@@ -0,0 +1,228 @@
<lexer>
<config>
<name>Mojo</name>
<alias>mojo</alias>
<alias>🔥</alias>
<filename>*.mojo</filename>
<filename>*.🔥</filename>
<mime_type>text/x-mojo</mime_type>
<mime_type>application/x-mojo</mime_type>
</config>
<rules>
<state name="root">
<rule pattern="\s+"><token type="TextWhitespace"/></rule>
<rule pattern="^(\s*)([rRuUbB]{,2})(&quot;&quot;&quot;(?:.|\n)*?&quot;&quot;&quot;)"><bygroups><token type="TextWhitespace"/><token type="LiteralStringAffix"/><token type="LiteralStringDoc"/></bygroups></rule>
<rule pattern="^(\s*)([rRuUbB]{,2})(&#x27;&#x27;&#x27;(?:.|\n)*?&#x27;&#x27;&#x27;)"><bygroups><token type="TextWhitespace"/><token type="LiteralStringAffix"/><token type="LiteralStringDoc"/></bygroups></rule>
<rule pattern="\A#!.+$"><token type="CommentHashbang"/></rule>
<rule pattern="#.*$"><token type="CommentSingle"/></rule>
<rule pattern="\\\n"><token type="TextWhitespace"/></rule>
<rule pattern="\\"><token type="TextWhitespace"/></rule>
<rule><include state="keywords"/></rule>
<rule><include state="soft-keywords"/></rule>
<rule pattern="(alias)(\s+)"><bygroups><token type="Keyword"/><token type="TextWhitespace"/></bygroups><push state="varname"/></rule>
<rule pattern="(var)(\s+)"><bygroups><token type="Keyword"/><token type="TextWhitespace"/></bygroups><push state="varname"/></rule>
<rule pattern="(def)(\s+)"><bygroups><token type="Keyword"/><token type="TextWhitespace"/></bygroups><push state="funcname"/></rule>
<rule pattern="(fn)(\s+)"><bygroups><token type="Keyword"/><token type="TextWhitespace"/></bygroups><push state="funcname"/></rule>
<rule pattern="(class)(\s+)"><bygroups><token type="Keyword"/><token type="TextWhitespace"/></bygroups><push state="classname"/></rule>
<rule pattern="(struct)(\s+)"><bygroups><token type="Keyword"/><token type="TextWhitespace"/></bygroups><push state="structname"/></rule>
<rule pattern="(trait)(\s+)"><bygroups><token type="Keyword"/><token type="TextWhitespace"/></bygroups><push state="structname"/></rule>
<rule pattern="(from)(\s+)"><bygroups><token type="KeywordNamespace"/><token type="TextWhitespace"/></bygroups><push state="fromimport"/></rule>
<rule pattern="(import)(\s+)"><bygroups><token type="KeywordNamespace"/><token type="TextWhitespace"/></bygroups><push state="import"/></rule>
<rule><include state="expr"/></rule>
</state>
<state name="expr">
<rule pattern="(?i)(rf|fr)(&quot;&quot;&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><combined state="rfstringescape" state="tdqf"/></rule>
<rule pattern="(?i)(rf|fr)(&#x27;&#x27;&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><combined state="rfstringescape" state="tsqf"/></rule>
<rule pattern="(?i)(rf|fr)(&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><combined state="rfstringescape" state="dqf"/></rule>
<rule pattern="(?i)(rf|fr)(&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><combined state="rfstringescape" state="sqf"/></rule>
<rule pattern="([fF])(&quot;&quot;&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><combined state="fstringescape" state="tdqf"/></rule>
<rule pattern="([fF])(&#x27;&#x27;&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><combined state="fstringescape" state="tsqf"/></rule>
<rule pattern="([fF])(&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><combined state="fstringescape" state="dqf"/></rule>
<rule pattern="([fF])(&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><combined state="fstringescape" state="sqf"/></rule>
<rule pattern="(?i)(rb|br|r)(&quot;&quot;&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><push state="tdqs"/></rule>
<rule pattern="(?i)(rb|br|r)(&#x27;&#x27;&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><push state="tsqs"/></rule>
<rule pattern="(?i)(rb|br|r)(&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><push state="dqs"/></rule>
<rule pattern="(?i)(rb|br|r)(&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><push state="sqs"/></rule>
<rule pattern="([uU]?)(&quot;&quot;&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><combined state="stringescape" state="tdqs"/></rule>
<rule pattern="([uU]?)(&#x27;&#x27;&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><combined state="stringescape" state="tsqs"/></rule>
<rule pattern="([uU]?)(&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><combined state="stringescape" state="dqs"/></rule>
<rule pattern="([uU]?)(&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><combined state="stringescape" state="sqs"/></rule>
<rule pattern="([bB])(&quot;&quot;&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><combined state="bytesescape" state="tdqs"/></rule>
<rule pattern="([bB])(&#x27;&#x27;&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><combined state="bytesescape" state="tsqs"/></rule>
<rule pattern="([bB])(&quot;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringDouble"/></bygroups><combined state="bytesescape" state="dqs"/></rule>
<rule pattern="([bB])(&#x27;)"><bygroups><token type="LiteralStringAffix"/><token type="LiteralStringSingle"/></bygroups><combined state="bytesescape" state="sqs"/></rule>
<rule pattern="[^\S\n]+"><token type="Text"/></rule>
<rule><include state="numbers"/></rule>
<rule pattern="!=|==|&lt;&lt;|&gt;&gt;|:=|[-~+/*%=&lt;&gt;&amp;^|.]"><token type="Operator"/></rule>
<rule pattern="([]{}:\(\),;[])+"><token type="Punctuation"/></rule>
<rule pattern="(in|is|and|or|not)\b"><token type="OperatorWord"/></rule>
<rule><include state="expr-keywords"/></rule>
<rule><include state="builtins"/></rule>
<rule><include state="magicfuncs"/></rule>
<rule><include state="magicvars"/></rule>
<rule><include state="name"/></rule>
</state>
<state name="expr-inside-fstring">
<rule pattern="[{([]"><token type="Punctuation"/><push state="expr-inside-fstring-inner"/></rule>
<rule pattern="(=\s*)?(\![sraf])?\}"><token type="LiteralStringInterpol"/><pop depth="1"/></rule>
<rule pattern="(=\s*)?(\![sraf])?:"><token type="LiteralStringInterpol"/><pop depth="1"/></rule>
<rule pattern="\s+"><token type="TextWhitespace"/></rule>
<rule><include state="expr"/></rule>
</state>
<state name="expr-inside-fstring-inner">
<rule pattern="[{([]"><token type="Punctuation"/><push state="expr-inside-fstring-inner"/></rule>
<rule pattern="[])}]"><token type="Punctuation"/><pop depth="1"/></rule>
<rule pattern="\s+"><token type="TextWhitespace"/></rule>
<rule><include state="expr"/></rule>
</state>
<state name="expr-keywords">
<rule pattern="(async\ for|async\ with|await|else|for|if|lambda|yield|yield\ from)\b"><token type="Keyword"/></rule>
<rule pattern="(True|False|None)\b"><token type="KeywordConstant"/></rule>
</state>
<state name="keywords">
<rule pattern="(assert|async|await|borrowed|break|continue|del|elif|else|except|finally|for|global|if|lambda|pass|raise|nonlocal|return|try|while|yield|yield\ from|as|with)\b"><token type="Keyword"/></rule>
<rule pattern="(True|False|None)\b"><token type="KeywordConstant"/></rule>
</state>
<state name="soft-keywords">
<rule pattern="(^[ \t]*)(match|case)\b(?![ \t]*(?:[:,;=^&amp;|@~)\]}]|(?:and|as|assert|async|await|break|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|nonlocal|not|or|pass|raise|return|try|while|with|yield)\b))"><bygroups><token type="TextWhitespace"/><token type="Keyword"/></bygroups><push state="soft-keywords-inner"/></rule>
</state>
<state name="soft-keywords-inner">
<rule pattern="(\s+)([^\n_]*)(_\b)"><bygroups><token type="TextWhitespace"/><usingself state="root"/><token type="Keyword"/></bygroups></rule>
<rule><pop depth="1"/></rule>
</state>
<state name="builtins">
<rule pattern="(?&lt;!\.)(__import__|abs|aiter|all|any|bin|bool|bytearray|breakpoint|bytes|callable|chr|classmethod|compile|complex|delattr|dict|dir|divmod|enumerate|eval|filter|float|format|frozenset|getattr|globals|hasattr|hash|hex|id|input|int|isinstance|issubclass|iter|len|list|locals|map|max|memoryview|min|next|object|oct|open|ord|pow|print|property|range|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|vars|zip|AnyType|Coroutine|DType|Error|Int|List|ListLiteral|Scalar|Int8|UInt8|Int16|UInt16|Int32|UInt32|Int64|UInt64|BFloat16|Float16|Float32|Float64|SIMD|String|Tensor|Tuple|Movable|Copyable|CollectionElement)\b"><token type="NameBuiltin"/></rule>
<rule pattern="(?&lt;!\.)(self|Ellipsis|NotImplemented|cls)\b"><token type="NameBuiltinPseudo"/></rule>
<rule pattern="(?&lt;!\.)(Error)\b"><token type="NameException"/></rule>
</state>
<state name="magicfuncs">
<rule pattern="(__abs__|__add__|__aenter__|__aexit__|__aiter__|__and__|__anext__|__await__|__bool__|__bytes__|__call__|__complex__|__contains__|__del__|__delattr__|__delete__|__delitem__|__dir__|__divmod__|__enter__|__eq__|__exit__|__float__|__floordiv__|__format__|__ge__|__get__|__getattr__|__getattribute__|__getitem__|__gt__|__hash__|__iadd__|__iand__|__ifloordiv__|__ilshift__|__imatmul__|__imod__|__imul__|__index__|__init__|__instancecheck__|__int__|__invert__|__ior__|__ipow__|__irshift__|__isub__|__iter__|__itruediv__|__ixor__|__le__|__len__|__length_hint__|__lshift__|__lt__|__matmul__|__missing__|__mod__|__mul__|__ne__|__neg__|__new__|__next__|__or__|__pos__|__pow__|__prepare__|__radd__|__rand__|__rdivmod__|__repr__|__reversed__|__rfloordiv__|__rlshift__|__rmatmul__|__rmod__|__rmul__|__ror__|__round__|__rpow__|__rrshift__|__rshift__|__rsub__|__rtruediv__|__rxor__|__set__|__setattr__|__setitem__|__str__|__sub__|__subclasscheck__|__truediv__|__xor__)\b"><token type="NameFunctionMagic"/></rule>
</state>
<state name="magicvars">
<rule pattern="(__annotations__|__bases__|__class__|__closure__|__code__|__defaults__|__dict__|__doc__|__file__|__func__|__globals__|__kwdefaults__|__module__|__mro__|__name__|__objclass__|__qualname__|__self__|__slots__|__weakref__)\b"><token type="NameVariableMagic"/></rule>
</state>
<state name="numbers">
<rule pattern="(\d(?:_?\d)*\.(?:\d(?:_?\d)*)?|(?:\d(?:_?\d)*)?\.\d(?:_?\d)*)([eE][+-]?\d(?:_?\d)*)?"><token type="LiteralNumberFloat"/></rule>
<rule pattern="\d(?:_?\d)*[eE][+-]?\d(?:_?\d)*j?"><token type="LiteralNumberFloat"/></rule>
<rule pattern="0[oO](?:_?[0-7])+"><token type="LiteralNumberOct"/></rule>
<rule pattern="0[bB](?:_?[01])+"><token type="LiteralNumberBin"/></rule>
<rule pattern="0[xX](?:_?[a-fA-F0-9])+"><token type="LiteralNumberHex"/></rule>
<rule pattern="\d(?:_?\d)*"><token type="LiteralNumberInteger"/></rule>
</state>
<state name="name">
<rule pattern="@[_\p{L}][_\p{L}\p{N}]*(\s*\.\s*[_\p{L}][_\p{L}\p{N}]*)*"><token type="NameDecorator"/></rule>
<rule pattern="@"><token type="Operator"/></rule>
<rule pattern="[_\p{L}][_\p{L}\p{N}]*(\s*\.\s*[_\p{L}][_\p{L}\p{N}]*)*"><token type="Name"/></rule>
</state>
<state name="varname">
<rule pattern="[_\p{L}][_\p{L}\p{N}]*(\s*\.\s*[_\p{L}][_\p{L}\p{N}]*)*"><token type="NameVariable"/><pop depth="1"/></rule>
</state>
<state name="funcname">
<rule><include state="magicfuncs"/></rule>
<rule pattern="[_\p{L}][_\p{L}\p{N}]*(\s*\.\s*[_\p{L}][_\p{L}\p{N}]*)*"><token type="NameFunction"/><pop depth="1"/></rule>
<rule><pop depth="1"/></rule>
</state>
<state name="classname">
<rule pattern="[_\p{L}][_\p{L}\p{N}]*(\s*\.\s*[_\p{L}][_\p{L}\p{N}]*)*"><token type="NameClass"/><pop depth="1"/></rule>
</state>
<state name="structname">
<rule pattern="[_\p{L}][_\p{L}\p{N}]*(\s*\.\s*[_\p{L}][_\p{L}\p{N}]*)*"><token type="NameClass"/><pop depth="1"/></rule>
</state>
<state name="import">
<rule pattern="(\s+)(as)(\s+)"><bygroups><token type="TextWhitespace"/><token type="Keyword"/><token type="TextWhitespace"/></bygroups></rule>
<rule pattern="\."><token type="NameNamespace"/></rule>
<rule pattern="[_\p{L}][_\p{L}\p{N}]*(\s*\.\s*[_\p{L}][_\p{L}\p{N}]*)*"><token type="NameNamespace"/></rule>
<rule pattern="(\s*)(,)(\s*)"><bygroups><token type="TextWhitespace"/><token type="Operator"/><token type="TextWhitespace"/></bygroups></rule>
<rule><pop depth="1"/></rule>
</state>
<state name="fromimport">
<rule pattern="(\s+)(import)\b"><bygroups><token type="TextWhitespace"/><token type="KeywordNamespace"/></bygroups><pop depth="1"/></rule>
<rule pattern="\."><token type="NameNamespace"/></rule>
<rule pattern="None\b"><token type="KeywordConstant"/><pop depth="1"/></rule>
<rule pattern="[_\p{L}][_\p{L}\p{N}]*(\s*\.\s*[_\p{L}][_\p{L}\p{N}]*)*"><token type="NameNamespace"/></rule>
<rule><pop depth="1"/></rule>
</state>
<state name="rfstringescape">
<rule pattern="\{\{"><token type="LiteralStringEscape"/></rule>
<rule pattern="\}\}"><token type="LiteralStringEscape"/></rule>
</state>
<state name="fstringescape">
<rule><include state="rfstringescape"/></rule>
<rule><include state="stringescape"/></rule>
</state>
<state name="bytesescape">
<rule pattern="\\([\\abfnrtv&quot;\&#x27;]|\n|x[a-fA-F0-9]{2}|[0-7]{1,3})"><token type="LiteralStringEscape"/></rule>
</state>
<state name="stringescape">
<rule pattern="\\(N\{.*?\}|u[a-fA-F0-9]{4}|U[a-fA-F0-9]{8})"><token type="LiteralStringEscape"/></rule>
<rule><include state="bytesescape"/></rule>
</state>
<state name="fstrings-single">
<rule pattern="\}"><token type="LiteralStringInterpol"/></rule>
<rule pattern="\{"><token type="LiteralStringInterpol"/><push state="expr-inside-fstring"/></rule>
<rule pattern="[^\\\&#x27;&quot;{}\n]+"><token type="LiteralStringSingle"/></rule>
<rule pattern="[\&#x27;&quot;\\]"><token type="LiteralStringSingle"/></rule>
</state>
<state name="fstrings-double">
<rule pattern="\}"><token type="LiteralStringInterpol"/></rule>
<rule pattern="\{"><token type="LiteralStringInterpol"/><push state="expr-inside-fstring"/></rule>
<rule pattern="[^\\\&#x27;&quot;{}\n]+"><token type="LiteralStringDouble"/></rule>
<rule pattern="[\&#x27;&quot;\\]"><token type="LiteralStringDouble"/></rule>
</state>
<state name="strings-single">
<rule pattern="%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?[hlL]?[E-GXc-giorsaux%]"><token type="LiteralStringInterpol"/></rule>
<rule pattern="\{((\w+)((\.\w+)|(\[[^\]]+\]))*)?(\![sra])?(\:(.?[&lt;&gt;=\^])?[-+ ]?#?0?(\d+)?,?(\.\d+)?[E-GXb-gnosx%]?)?\}"><token type="LiteralStringInterpol"/></rule>
<rule pattern="[^\\\&#x27;&quot;%{\n]+"><token type="LiteralStringSingle"/></rule>
<rule pattern="[\&#x27;&quot;\\]"><token type="LiteralStringSingle"/></rule>
<rule pattern="%|(\{{1,2})"><token type="LiteralStringSingle"/></rule>
</state>
<state name="strings-double">
<rule pattern="%(\(\w+\))?[-#0 +]*([0-9]+|[*])?(\.([0-9]+|[*]))?[hlL]?[E-GXc-giorsaux%]"><token type="LiteralStringInterpol"/></rule>
<rule pattern="\{((\w+)((\.\w+)|(\[[^\]]+\]))*)?(\![sra])?(\:(.?[&lt;&gt;=\^])?[-+ ]?#?0?(\d+)?,?(\.\d+)?[E-GXb-gnosx%]?)?\}"><token type="LiteralStringInterpol"/></rule>
<rule pattern="[^\\\&#x27;&quot;%{\n]+"><token type="LiteralStringDouble"/></rule>
<rule pattern="[\&#x27;&quot;\\]"><token type="LiteralStringDouble"/></rule>
<rule pattern="%|(\{{1,2})"><token type="LiteralStringDouble"/></rule>
</state>
<state name="dqf">
<rule pattern="&quot;"><token type="LiteralStringDouble"/><pop depth="1"/></rule>
<rule pattern="\\\\|\\&quot;|\\\n"><token type="LiteralStringEscape"/></rule>
<rule><include state="fstrings-double"/></rule>
</state>
<state name="sqf">
<rule pattern="&#x27;"><token type="LiteralStringSingle"/><pop depth="1"/></rule>
<rule pattern="\\\\|\\&#x27;|\\\n"><token type="LiteralStringEscape"/></rule>
<rule><include state="fstrings-single"/></rule>
</state>
<state name="dqs">
<rule pattern="&quot;"><token type="LiteralStringDouble"/><pop depth="1"/></rule>
<rule pattern="\\\\|\\&quot;|\\\n"><token type="LiteralStringEscape"/></rule>
<rule><include state="strings-double"/></rule>
</state>
<state name="sqs">
<rule pattern="&#x27;"><token type="LiteralStringSingle"/><pop depth="1"/></rule>
<rule pattern="\\\\|\\&#x27;|\\\n"><token type="LiteralStringEscape"/></rule>
<rule><include state="strings-single"/></rule>
</state>
<state name="tdqf">
<rule pattern="&quot;&quot;&quot;"><token type="LiteralStringDouble"/><pop depth="1"/></rule>
<rule><include state="fstrings-double"/></rule>
<rule pattern="\n"><token type="LiteralStringDouble"/></rule>
</state>
<state name="tsqf">
<rule pattern="&#x27;&#x27;&#x27;"><token type="LiteralStringSingle"/><pop depth="1"/></rule>
<rule><include state="fstrings-single"/></rule>
<rule pattern="\n"><token type="LiteralStringSingle"/></rule>
</state>
<state name="tdqs">
<rule pattern="&quot;&quot;&quot;"><token type="LiteralStringDouble"/><pop depth="1"/></rule>
<rule><include state="strings-double"/></rule>
<rule pattern="\n"><token type="LiteralStringDouble"/></rule>
</state>
<state name="tsqs">
<rule pattern="&#x27;&#x27;&#x27;"><token type="LiteralStringSingle"/><pop depth="1"/></rule>
<rule><include state="strings-single"/></rule>
<rule pattern="\n"><token type="LiteralStringSingle"/></rule>
</state>
</rules>
</lexer>
@@ -0,0 +1,83 @@
<lexer>
<config>
<name>MoonScript</name>
<alias>moonscript</alias>
<alias>moon</alias>
<filename>*.moon</filename>
<mime_type>text/x-moonscript</mime_type>
<mime_type>application/x-moonscript</mime_type>
</config>
<rules>
<state name="root">
<rule pattern="#!(.*?)$"><token type="CommentPreproc"/></rule>
<rule><push state="base"/></rule>
</state>
<state name="base">
<rule pattern="--.*$"><token type="CommentSingle"/></rule>
<rule pattern="(?i)(\d*\.\d+|\d+\.\d*)(e[+-]?\d+)?"><token type="LiteralNumberFloat"/></rule>
<rule pattern="(?i)\d+e[+-]?\d+"><token type="LiteralNumberFloat"/></rule>
<rule pattern="(?i)0x[0-9a-f]*"><token type="LiteralNumberHex"/></rule>
<rule pattern="\d+"><token type="LiteralNumberInteger"/></rule>
<rule pattern="\n"><token type="TextWhitespace"/></rule>
<rule pattern="[^\S\n]+"><token type="Text"/></rule>
<rule pattern="(?s)\[(=*)\[.*?\]\1\]"><token type="LiteralString"/></rule>
<rule pattern="(-&gt;|=&gt;)"><token type="NameFunction"/></rule>
<rule pattern=":[a-zA-Z_]\w*"><token type="NameVariable"/></rule>
<rule pattern="(==|!=|~=|&lt;=|&gt;=|\.\.\.|\.\.|[=+\-*/%^&lt;&gt;#!.\\:])"><token type="Operator"/></rule>
<rule pattern="[;,]"><token type="Punctuation"/></rule>
<rule pattern="[\[\]{}()]"><token type="KeywordType"/></rule>
<rule pattern="[a-zA-Z_]\w*:"><token type="NameVariable"/></rule>
<rule pattern="(class|extends|if|then|super|do|with|import|export|while|elseif|return|for|in|from|when|using|else|switch|break)\b"><token type="Keyword"/></rule>
<rule pattern="(true|false|nil)\b"><token type="KeywordConstant"/></rule>
<rule pattern="(and|or|not)\b"><token type="OperatorWord"/></rule>
<rule pattern="(self)\b"><token type="NameBuiltinPseudo"/></rule>
<rule pattern="@@?([a-zA-Z_]\w*)?"><token type="NameVariableClass"/></rule>
<rule pattern="[A-Z]\w*"><token type="NameClass"/></rule>
<rule pattern="(_G|_VERSION|assert|collectgarbage|dofile|error|getmetatable|ipairs|load|loadfile|next|pairs|pcall|print|rawequal|rawget|rawlen|rawset|select|setmetatable|tonumber|tostring|type|warn|xpcall|bit32\.arshift|bit32\.band|bit32\.bnot|bit32\.bor|bit32\.btest|bit32\.bxor|bit32\.extract|bit32\.lrotate|bit32\.lshift|bit32\.replace|bit32\.rrotate|bit32\.rshift|coroutine\.close|coroutine\.create|coroutine\.isyieldable|coroutine\.resume|coroutine\.running|coroutine\.status|coroutine\.wrap|coroutine\.yield|debug\.debug|debug\.gethook|debug\.getinfo|debug\.getlocal|debug\.getmetatable|debug\.getregistry|debug\.getupvalue|debug\.getuservalue|debug\.sethook|debug\.setlocal|debug\.setmetatable|debug\.setupvalue|debug\.setuservalue|debug\.traceback|debug\.upvalueid|debug\.upvaluejoin|io\.close|io\.flush|io\.input|io\.lines|io\.open|io\.output|io\.popen|io\.read|io\.stderr|io\.stdin|io\.stdout|io\.tmpfile|io\.type|io\.write|math\.abs|math\.acos|math\.asin|math\.atan|math\.atan2|math\.ceil|math\.cos|math\.cosh|math\.deg|math\.exp|math\.floor|math\.fmod|math\.frexp|math\.huge|math\.ldexp|math\.log|math\.max|math\.maxinteger|math\.min|math\.mininteger|math\.modf|math\.pi|math\.pow|math\.rad|math\.random|math\.randomseed|math\.sin|math\.sinh|math\.sqrt|math\.tan|math\.tanh|math\.tointeger|math\.type|math\.ult|package\.config|package\.cpath|package\.loaded|package\.loadlib|package\.path|package\.preload|package\.searchers|package\.searchpath|require|os\.clock|os\.date|os\.difftime|os\.execute|os\.exit|os\.getenv|os\.remove|os\.rename|os\.setlocale|os\.time|os\.tmpname|string\.byte|string\.char|string\.dump|string\.find|string\.format|string\.gmatch|string\.gsub|string\.len|string\.lower|string\.match|string\.pack|string\.packsize|string\.rep|string\.reverse|string\.sub|string\.unpack|string\.upper|table\.concat|table\.insert|table\.move|table\.pack|table\.remove|table\.sort|table\.unpack|utf8\.char|utf8\.charpattern|utf8\.codepoint|utf8\.codes|utf8\.len|utf8\.offset)\b"><token type="NameBuiltin"/></rule>
<rule pattern="[A-Za-z_]\w*"><token type="Name"/></rule>
<rule pattern="&#x27;"><token type="LiteralStringSingle"/><combined state="stringescape" state="sqs"/></rule>
<rule pattern="&quot;"><token type="LiteralStringDouble"/><combined state="stringescape" state="dqs"/></rule>
</state>
<state name="stringescape">
<rule pattern="\\([abfnrtv\\&quot;\&#x27;]|\d{1,3})"><token type="LiteralStringEscape"/></rule>
</state>
<state name="sqs">
<rule pattern="&#x27;"><token type="LiteralStringSingle"/><pop depth="1"/></rule>
<rule pattern="[^\\&#x27;]+"><token type="LiteralString"/></rule>
</state>
<state name="dqs">
<rule pattern="&quot;"><token type="LiteralStringDouble"/><pop depth="1"/></rule>
<rule pattern="[^\\&quot;]+"><token type="LiteralString"/></rule>
</state>
<state name="ws">
<rule pattern="(?:--\[(?&lt;level&gt;=*)\[[\w\W]*?\](\k&lt;level&gt;)\])"><token type="CommentMultiline"/></rule>
<rule pattern="(?:--.*$)"><token type="CommentSingle"/></rule>
<rule pattern="(?:\s+)"><token type="TextWhitespace"/></rule>
</state>
<state name="varname">
<rule><include state="ws"/></rule>
<rule pattern="\.\."><token type="Operator"/><pop depth="1"/></rule>
<rule pattern="[.:]"><token type="Punctuation"/></rule>
<rule pattern="(?:[^\W\d]\w*)(?=(?:(?:--\[(?&lt;level&gt;=*)\[[\w\W]*?\](\k&lt;level&gt;)\])|(?:--.*$)|(?:\s+))*[.:])"><token type="NameProperty"/></rule>
<rule pattern="(?:[^\W\d]\w*)(?=(?:(?:--\[(?&lt;level&gt;=*)\[[\w\W]*?\](\k&lt;level&gt;)\])|(?:--.*$)|(?:\s+))*\()"><token type="NameFunction"/><pop depth="1"/></rule>
<rule pattern="(?:[^\W\d]\w*)"><token type="NameProperty"/><pop depth="1"/></rule>
</state>
<state name="funcname">
<rule><include state="ws"/></rule>
<rule pattern="[.:]"><token type="Punctuation"/></rule>
<rule pattern="(?:[^\W\d]\w*)(?=(?:(?:--\[(?&lt;level&gt;=*)\[[\w\W]*?\](\k&lt;level&gt;)\])|(?:--.*$)|(?:\s+))*[.:])"><token type="NameClass"/></rule>
<rule pattern="(?:[^\W\d]\w*)"><token type="NameFunction"/><pop depth="1"/></rule>
<rule pattern="\("><token type="Punctuation"/><pop depth="1"/></rule>
</state>
<state name="goto">
<rule><include state="ws"/></rule>
<rule pattern="(?:[^\W\d]\w*)"><token type="NameLabel"/><pop depth="1"/></rule>
</state>
<state name="label">
<rule><include state="ws"/></rule>
<rule pattern="::"><token type="Punctuation"/><pop depth="1"/></rule>
<rule pattern="(?:[^\W\d]\w*)"><token type="NameLabel"/></rule>
</state>
</rules>
</lexer>
@@ -58,6 +58,9 @@
<rule pattern="\$[^\s;#()]+">
<token type="NameVariable"/>
</rule>
<rule pattern="(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b)">
<token type="Name"/>
</rule>
<rule pattern="([a-z0-9.-]+)(:)([0-9]+)">
<bygroups>
<token type="Name"/>
+121
View File
@@ -0,0 +1,121 @@
<lexer>
<config>
<name>Nu</name>
<alias>nu</alias>
<filename>*.nu</filename>
<mime_type>text/plain</mime_type>
</config>
<rules>
<state name="root">
<rule><include state="basic" /></rule>
<rule><include state="data" /></rule>
</state>
<state name="basic">
<rule
pattern="\b(alias|all|ansi|ansi gradient|ansi link|ansi strip|any|append|ast|attr category|attr deprecated|attr example|attr search-terms|banner|bits|bits and|bits not|bits or|bits rol|bits ror|bits shl|bits shr|bits xor|break|bytes|bytes add|bytes at|bytes build|bytes collect|bytes ends-with|bytes index-of|bytes length|bytes remove|bytes replace|bytes reverse|bytes split|bytes starts-with|cal|cd|char|chunk-by|chunks|clear|collect|columns|commandline|commandline edit|commandline get-cursor|commandline set-cursor|compact|complete|config|config env|config flatten|config nu|config reset|config use-colors|const|continue|cp|date|date format|date from-human|date humanize|date list-timezone|date now|date to-timezone|debug|debug env|debug info|debug profile|decode|decode base32|decode base32hex|decode base64|decode hex|def|default|describe|detect columns|do|drop|drop column|drop nth|du|each|each while|echo|encode|encode base32|encode base32hex|encode base64|encode hex|enumerate|error make|every|exec|exit|explain|explore|export|export alias|export const|export def|export extern|export module|export use|export-env|extern|fill|filter|find|first|flatten|for|format|format bits|format date|format duration|format filesize|format number|format pattern|from|from csv|from json|from msgpack|from msgpackz|from nuon|from ods|from ssv|from toml|from tsv|from url|from xlsx|from xml|from yaml|from yml|generate|get|glob|grid|group-by|hash|hash md5|hash sha256|headers|help|help aliases|help commands|help escapes|help externs|help modules|help operators|help pipe-and-redirect|hide|hide-env|histogram|history|history import|history session|http|http delete|http get|http head|http options|http patch|http post|http put|if|ignore|input|input list|input listen|insert|inspect|interleave|into|into binary|into bool|into cell-path|into datetime|into duration|into filesize|into float|into glob|into int|into record|into sqlite|into string|into value|is-admin|is-empty|is-not-empty|is-terminal|items|job|job flush|job id|job kill|job list|job recv|job send|job spawn|job tag|job unfreeze|join|keybindings|keybindings default|keybindings list|keybindings listen|kill|last|length|let|let-env|lines|load-env|loop|ls|match|math|math abs|math arccos|math arccosh|math arcsin|math arcsinh|math arctan|math arctanh|math avg|math ceil|math cos|math cosh|math exp|math floor|math ln|math log|math max|math median|math min|math mode|math product|math round|math sin|math sinh|math sqrt|math stddev|math sum|math tan|math tanh|math variance|merge|merge deep|metadata|metadata access|metadata set|mkdir|mktemp|module|move|mut|mv|nu-check|nu-highlight|open|overlay|overlay hide|overlay list|overlay new|overlay use|panic|par-each|parse|path|path basename|path dirname|path exists|path expand|path join|path parse|path relative-to|path self|path split|path type|plugin|plugin add|plugin list|plugin rm|plugin stop|plugin use|port|prepend|print|ps|pwd|query db|random|random binary|random bool|random chars|random dice|random float|random int|random uuid|reduce|reject|rename|return|reverse|rm|roll|roll down|roll left|roll right|roll up|rotate|run-external|save|schema|scope|scope aliases|scope commands|scope engine-stats|scope externs|scope modules|scope variables|select|seq|seq char|seq date|shuffle|skip|skip until|skip while|sleep|slice|sort|sort-by|source|source-env|split|split cell-path|split chars|split column|split list|split row|split words|start|stor|stor create|stor delete|stor export|stor import|stor insert|stor open|stor reset|stor update|str|str camel-case|str capitalize|str contains|str distance|str downcase|str ends-with|str expand|str index-of|str join|str kebab-case|str length|str pascal-case|str replace|str reverse|str screaming-snake-case|str snake-case|str starts-with|str stats|str substring|str title-case|str trim|str upcase|sys|sys cpu|sys disks|sys host|sys mem|sys net|sys temp|sys users|table|take|take until|take while|tee|term|term query|term size|timeit|to|to csv|to html|to json|to md|to msgpack|to msgpackz|to nuon|to text|to toml|to tsv|to xml|to yaml|to yml|touch|transpose|try|tutor|ulimit|uname|uniq|uniq-by|update|update cells|upsert|url|url build-query|url decode|url encode|url join|url parse|url split-query|use|values|version|version check|view|view blocks|view files|view ir|view source|view span|watch|where|which|while|whoami|window|with-env|wrap|zip)(\s*)\b"
><bygroups><token type="Keyword" /><token
type="TextWhitespace"
/></bygroups></rule>
<rule pattern="\A#!.+\n"><token type="CommentHashbang" /></rule>
<rule pattern="#.*\n"><token type="CommentSingle" /></rule>
<rule pattern="\\[\w\W]"><token type="LiteralStringEscape" /></rule>
<rule pattern="(\b\w+)(\s*)(\+?=)"><bygroups><token
type="NameVariable"
/><token type="TextWhitespace" /><token
type="Operator"
/></bygroups></rule>
<rule pattern="[\[\]{}()=]"><token type="Operator" /></rule>
<rule pattern="&lt;&lt;&lt;"><token type="Operator" /></rule>
<rule pattern="&lt;&lt;-?\s*(\&#x27;?)\\?(\w+)[\w\W]+?\2"><token
type="LiteralString"
/></rule>
<rule pattern="&amp;&amp;|\|\|"><token type="Operator" /></rule>
<rule pattern="\$[a-zA-Z_]\w*"><token type="NameVariable" /></rule>
</state>
<state name="data">
<rule pattern="\$&quot;"><token type="LiteralStringDouble" /><push
state="interpolated_string"
/></rule>
<rule pattern="(?s)&quot;(\\.|[^&quot;\\])*&quot;"><token
type="LiteralStringDouble"
/></rule>
<rule pattern="&quot;"><token type="LiteralStringDouble" /><push
state="string"
/></rule>
<rule pattern="(?s)\$&#x27;(\\\\|\\[0-7]+|\\.|[^&#x27;\\])*&#x27;"><token
type="LiteralStringSingle"
/></rule>
<rule pattern="(?s)&#x27;.*?&#x27;"><token
type="LiteralStringSingle"
/></rule>
<rule pattern=";"><token type="Punctuation" /></rule>
<rule pattern="&amp;"><token type="Punctuation" /></rule>
<rule pattern="\|"><token type="Punctuation" /></rule>
<rule pattern="\s+"><token type="TextWhitespace" /></rule>
<rule pattern="\d+\b"><token type="LiteralNumber" /></rule>
<rule pattern="[^=\s\[\]{}()$&quot;\&#x27;`\\&lt;&amp;|;]+"><token
type="Text"
/></rule>
<rule pattern="&lt;"><token type="Text" /></rule>
</state>
<state name="string">
<rule pattern="&quot;"><token type="LiteralStringDouble" /><pop
depth="1"
/></rule>
<rule pattern="(?s)(\\\\|\\[0-7]+|\\.|[^&quot;\\$])+"><token
type="LiteralStringDouble"
/></rule>
</state>
<state name="interpolated_string">
<rule pattern="&quot;"><token type="LiteralStringDouble" /><pop
depth="1"
/></rule>
<rule pattern="\("><token type="LiteralStringInterpol" /><push
state="interpolation"
/></rule>
<rule pattern="(?s)(\\\\|\\[0-7]+|\\.|[^&quot;\\(])+"><token
type="LiteralStringDouble"
/></rule>
</state>
<state name="interpolation">
<rule pattern="\)"><token type="LiteralStringInterpol" /><pop
depth="1"
/></rule>
<rule><include state="root" /></rule>
</state>
<state name="curly">
<rule pattern="\}"><token type="LiteralStringInterpol" /><pop
depth="1"
/></rule>
<rule pattern=":-"><token type="Keyword" /></rule>
<rule pattern="\w+"><token type="NameVariable" /></rule>
<rule pattern="[^}:&quot;\&#x27;`$\\]+"><token
type="Punctuation"
/></rule>
<rule pattern=":"><token type="Punctuation" /></rule>
<rule><include state="root" /></rule>
</state>
<state name="paren">
<rule pattern="\)"><token type="Keyword" /><pop depth="1" /></rule>
<rule><include state="root" /></rule>
</state>
<state name="math">
<rule pattern="\)\)"><token type="Keyword" /><pop depth="1" /></rule>
<rule pattern="\*\*|\|\||&lt;&lt;|&gt;&gt;|[-+*/%^|&amp;&lt;&gt;]"><token
type="Operator"
/></rule>
<rule pattern="\d+#[\da-zA-Z]+"><token type="LiteralNumber" /></rule>
<rule pattern="\d+#(?! )"><token type="LiteralNumber" /></rule>
<rule pattern="0[xX][\da-fA-F]+"><token type="LiteralNumber" /></rule>
<rule pattern="\d+"><token type="LiteralNumber" /></rule>
<rule pattern="[a-zA-Z_]\w*"><token type="NameVariable" /></rule>
<rule><include state="root" /></rule>
</state>
<state name="backticks">
<rule pattern="`"><token type="LiteralStringBacktick" /><pop
depth="1"
/></rule>
<rule><include state="root" /></rule>
</state>
</rules>
</lexer>
@@ -31,12 +31,9 @@
<rule pattern="\{[$].*?\}|\{[-](NOD|EXT|OBJ).*?\}|\([*][$].*?[*]\)">
<token type="CommentPreproc" />
</rule>
<!-- Comment Single -->
<rule pattern="(//.*?)(\n)">
<bygroups>
<token type="CommentSingle" />
<token type="TextWhitespace" />
</bygroups>
<!-- Comment -->
<rule pattern="//.*">
<token type="CommentSingle" />
</rule>
<!-- Comment Multiline Block -->
<rule pattern="\([*](.|\n)*?[*]\)">
@@ -41,6 +41,14 @@
<rule pattern="\b(as|assert|begin|class|constraint|do|done|downto|else|end|exception|external|false|for|fun|function|functor|if|in|include|inherit|initializer|lazy|let|match|method|module|mutable|new|object|of|open|private|raise|rec|sig|struct|then|to|true|try|type|value|val|virtual|when|while|with)\b">
<token type="Keyword"/>
</rule>
<rule pattern="({([a-z_]*)\|)([\s\S]+?)(?=\|\2})(\|\2})">
<bygroups>
<token type="LiteralStringAffix"/>
<token type="Ignore"/>
<token type="LiteralString"/>
<token type="LiteralStringAffix"/>
</bygroups>
</rule>
<rule pattern="(~|\}|\|]|\||\{&lt;|\{|`|_|]|\[\||\[&gt;|\[&lt;|\[|\?\?|\?|&gt;\}|&gt;]|&gt;|=|&lt;-|&lt;|;;|;|:&gt;|:=|::|:|\.\.|\.|-&gt;|-\.|-|,|\+|\*|\)|\(|&amp;&amp;|&amp;|#|!=)">
<token type="Operator"/>
</rule>
@@ -51,6 +51,20 @@
<rule pattern = "\#[a-zA-Z_]+\b">
<token type = "NameDecorator"/>
</rule>
<rule pattern = "^\#\+\w+\s*$">
<token type = "NameAttribute"/>
</rule>
<rule pattern = "^(\#\+\w+)(\s+)(\!)?([A-Za-z0-9-_!]+)(?:(,)(\!)?([A-Za-z0-9-_!]+))*\s*$">
<bygroups>
<token type = "NameAttribute"/>
<token type = "TextWhitespace"/>
<token type = "Operator"/>
<token type = "Name"/>
<token type = "Punctuation"/>
<token type = "Operator"/>
<token type = "Name"/>
</bygroups>
</rule>
<rule pattern = "\@(\([a-zA-Z_]+\b\s*.*\)|\(?[a-zA-Z_]+\)?)">
<token type = "NameAttribute"/>
</rule>
@@ -0,0 +1,176 @@
<lexer>
<config>
<name>RPGLE</name>
<alias>SQLRPGLE</alias>
<alias>RPG IV</alias>
<filename>*.RPGLE</filename>
<filename>*.rpgle</filename>
<filename>*.SQLRPGLE</filename>
<filename>*.sqlrpgle</filename>
<mime_type>text/x-rpgle</mime_type>
<mime_type>text/x-sqlrpgle</mime_type>
<case_insensitive>true</case_insensitive>
<analyse>
<regex pattern="^\*\*free$" score="0.9"/>
<regex pattern="ctl-opt" score="0.9"/>
<regex pattern="dcl-(ds|s|f|proc|pr|pi)" score="0.9"/>
<regex pattern="\*in[0-9][0-9]" score="0.5"/>
</analyse>
</config>
<rules>
<state name="root">
<rule pattern="\/\/.*">
<token type="Comment"/>
</rule>
<rule pattern="^\*\*free$">
<token type="CommentSpecial"/>
</rule>
<rule pattern="\*\*((ctdata|ftrans|altseq)(\s+\w+)?)?(\r|\n|\r\n)">
<token type="CommentSpecial"/> <!-- compile-time arrays at the end of the file, introduced by ** -->
<push state="compile-time-array"/>
</rule>
<rule pattern="(\*(all(g|oc|ow|sep|thread|u|x)?|altseq|alwblanknum|ascii|astfill|aut[lo]|basic|blank(s)?|caller|cancl|cdmy(0)?|change|char|cl|cmd(y|y0)?|cnowiden|cntrld|col|comp(at)?|concurrent|constants|constructor|convert|copyright|crt(bndrpg|rpgmod)|ct(data|lbdy|lspec)|cur(lib|sym)|cvt(data)?|cwiden|cymd(0)?|data|date(time)?|day(s)?|dclcase|ddm|debugio|dec|delete|det[cl]|dft|diag|dmy|dtaara|dump|end|entry(exit)?|equate|escape|eur(0)?|exact|exclude|excp|exp(dds|include)|ext(desc|dft)?|file(s)?|first|ftrans|full|gen|getin|graph(ic)?|hex|hival|hms|hours|ignore|ilerpg|in([0-9]{2}|H[1-9]|K[A-Y]|L[1-9]|LR|O[AGV]|U[1-8])?|INFO|INHERIT|INIT|INP(UT(ONLY|PACKED)?)?|INZ(OFL|SR)|ISO(0)?|JAVA|JIS|JOB(RUN(0|MIX|_DBCS|_JAVA|_MIXED)?)?|JUL|KEEP|KEY|LANGID(SHR|UNQ)|LDA|LGL|LIB(L|RCRTAUT)|LIKE(DS)?|LIST|LOCK|LONG(JOBRUN(0)?|JUL(0)?)|LOVAL|LVL[12]|MAX(DIGITS)?|MDY(0)?|MINUTES|MIXED(ASCII|EBCDIC)|MN|MODE|MODULE|MONTH(S)?|MS(ECONDS)?|M[A-Z]{3}[0-9]{4}|NATURAL|NEW|NEXT|NO(ALLOW|CHGDSLEN|COL|CVT(DATA)?|DATETIME|DEBUGIO|EXACT|EXPDDS|EXPINCLUDE|EXT|GEN|GRAPHIC|IND|INPUTPACKED|INZOFL|KEY|PASS|RMVCOMMENT|SECLVL|SHOWCPY|SHOWSKP|SRCSTMT|UNREF|VARCHAR|VARGRAPHIC|XREF|ZONED)?|NONE|NOTIFY|NULL(IND)?|OFF|OFL|OMIT|ON(EXIT|LY)?|OPCODE|OUT(PUT)?|OWNER|PARM(S)?|PCML|PDA|PEP|PGM(BDY)?|PLACE|PROC|PROGRAM|PSSR|RECORD|REQUIRE|RESDECPOS|RETVAL|RIGHTADJ|RMVCOMMENT|ROUTINE|SECLVL|SECONDS|SELF|SERIALIZE|SHOW(CPY|SKP)|SIZE|SNGLVL|SRC(MBRTXT|STMT)?|START|STATUS|STDCHARSIZE|STGMDL|STRICTKEYS|STRING|SYS|TBL|TERASPACE|TERM|THREAD_(CONCURRENT|SERIALIZE)|TOT[CL]|TRIM|UCS2|UNIQUE|UNREF|UNSET|UPDATE|USA(0)?|USE(DECEDIT)?|USER|USR(CTL|SPC)|UTF(8|16)?|V[0-9]R[0-9]M[0-9]|V[678]|VAR(CHAR|GRAPHIC|SIZE)?|WARN|XMLSAX|XML_(ATTR_(CHARS|NAME|PREDEF_REF|UCS2_REF)|CHARS|COMMENT|DOCTYPE_DECL|ENCODING_DECL|END_(ATTR|CDATA|DOCUMENT|ELEMENT)|EXCEPTION|PI_(DATA|TARGET)|PREDEF_REF|STANDALONE_DECL|START_(CDATA|DOCUMENT|ELEMENT)|UCS2_REF|UNKNOWN_(ATTR_REF|REF)|VERSION_INFO)|XREF|YEAR(S)?|YES|YMD(0)?|ZERO(S)?|ZONED|[DHMNSY]))\b">
<token type="Literal"/> <!-- Special values -->
</rule>
<rule pattern="\bexec\s+sql\b"> <!-- embedded SQL -->
<token type="Keyword"/>
<push state="exec-sql"/>
</rule>
<rule pattern="(%(abs|addr|alloc|bitand|bitnot|bitor|bitxor|char|charcount|check|checkr|concat|concatarr|data|date|days|dec|dech|decpos|diff|div|editc|editflt|editw|elem|eof|equal|error|fields|float|found|gen|graph|handler|hival|hours|int|inth|kds|left|len|list|lookup(lt|ge|gt|le)?|loval|lower|max|maxarr|min|minutes|minarr|months|mseconds|msg|nullind|occur|omitted|open|paddr|parms|parmnum|parser|passed|proc|range|realloc|rem|replace|right|scan|scanr|scanrpl|seconds|shtdn|size|split|sqrt|status|str|subarr|subdt|subst|target|this|time|timestamp|tlookup(lt|ge|gt|le)?|trim(l|r)?|ucs2|uns|unsh|upper|xfoot|xlate|xml|years))\b">
<token type="NameFunctionMagic"/> <!-- builtin functions -->
</rule>
<rule pattern="\b(ind|int|uns|(var)?char|bindec|float|packed|zoned|time(stamp)?|date|pointer|clob|blob|(var)?graph|object|(var)?ucs2)\b">
<token type="KeywordType"/> <!-- variable types -->
</rule>
<rule pattern="\b(dcl\-(ds|pi|proc|pr|[csf])|end\-(ds|pi|proc|pr)|ctl\-opt|const|value|to|downto|not)\b">
<token type="Keyword"/> <!-- Syntax keywords -->
</rule>
<rule pattern="\b(acq|add|adddur|alloc|and(gt|lt|eq|ne|ge|le)?|begsr|bitoff|biton|cab(gt|lt|eq|ne|ge|le)?|call(b|p)?|cas(gt|lt|eq|ne|ge|le)?|cat|chain|check|checkr|clear|close|commit|comp|data-gen|data-into|dealloc|define|delete|div|do((u|w)(gt|lt|eq|ne|ge|le)?)?|dsply|dump|else(if)?|end(cs|do|for|if|mon|sl|sr)?|eval(r|-corr)?|except|exfmt|exsr|extrct|feod|for(-each)?|force|goto|if(gt|lt|eq|ne|ge|le)?|in|iter|kfld|klist|leave(sr)?|lookup|m(hh|hl|lh|ll)zo|monitor|move[al]?|mult|mvr|next|occur|on-(error|excp|exit)|open|or(gt|lt|eq|ne|ge|le)?|other|out|parm|plist|post|read(c|e|p|pe)?|realloc|rel|reset|return|rolbk|scan|select|set(gt|ll|off|on)|shtdn|snd-msg|sorta|sqrt|sub(dur|st)?|tag|test[bnz]?|time|unlock|update|when(gt|lt|eq|ne|ge|le)?|when-i[ns]|write|xfoot|slate|xml-(into|sax)|z-(add|sub))\b">
<token type="Keyword"/> <!-- Operation codes -->
</rule>
<rule pattern="\b(alloc|altseq|ccsid|copy(nest|right)|cursym|dat(edit|fmt)|debug|dec(edit|prec)|dftname|expropts|extbinint|fltdiv|formsalign|ftrans|intprec|(no)?main|openopt|thread|timfmt|actgrp|alwnull|aut|bnddir|cvtopt|dateyy|dftactgrp|enbpfrcol|fixnbr|genlvl|indent|langid|optimize|option|pgminfo|prfdta|reqprexp|strseq|stgmdl|text|truncnbr|usrprf)\b">
<token type="KeywordReserved"/> <!-- ctl-opt (former H spec) -->
</rule>
<rule pattern="\b(alias|block|commit|charcount|data|datfmt|devid|disk|ext(desc|file|ind|mbr)|form(len|ofl)|handler|ignore|include|in(dds|fds|fsr)|keyed|keyloc|likefile|maxdev|oflind|pass|pgmname|plist|prefix|printer|prtctl|qualified|rafdata|recno|rename|save(ds|ind)|seq|sfile|sln|special|static|template|timfmt|usage|usropn|workstn)\b">
<token type="KeywordReserved"/> <!-- dcl-f (former F spec) -->
</rule>
<rule pattern="\b(\*(yes|no|natural|stdcharsize|(no)?cvt|ext(desc)?|inu[1-8]|char|only|file|noind|ext|compat|input|output|update|delete))\b">
<token type="Literal"/> <!-- F spec special values-->
</rule>
<rule pattern="\b(alias|align|alt|altseq|ascend|based|ccsid|class|const|ctdata|datfmt|descend|dim|dtaara|export|ext(fld|fmt|name|pgm|proc)?|fromfile|import|inz|len|like(ds|file|rec)?|noopt|nullind|occurs|opdesc|options|overlay|overload|packeven|perrcd|pos|prefix|procptr|psds|qualified|reqproto|rtnparm|samepos|static|template|timfmt|tofile|value|varying)\b">
<token type="KeywordReserved"/> <!-- Other keywords (not operation codes nor ctl-opt/H spec) -> mostly used with variables -->
</rule>
<rule pattern="(/(copy|define|eject|else|elseif|end-exec|end-free|endif|eof|exec|free|if|include|restore|set|space|title|undefine))\b">
<token type="CommentPreproc"/> <!-- Preprocessor instructions -->
</rule>
<rule pattern="\b([0-9]+((\.[0-9]?)(e[+-][0-9]+)?)?)\b">
<token type="LiteralNumber"/>
</rule>
<rule pattern="\bx'[0-9a-fA-F]*'">
<token type="LiteralString"/> <!-- Hex string -->
</rule>
<rule pattern="'(''|[^'])*'">
<token type="LiteralString"/>
</rule>
<rule pattern="[,:;\(\)\.]+">
<token type="Punctuation"/>
</rule>
<rule pattern="((\*\*)|(&lt;&gt;)|=|([&lt;&gt;\+\-\*\/]=?))+">
<token type="Operator"/> <!-- Arithmetic operators -->
</rule>
<rule pattern="\s">
<token type="TextWhitespace"/>
</rule>
<rule pattern=".">
<token type="Text"/>
</rule>
</state>
<state name="exec-sql">
<rule pattern=';'>
<token type="Punctuation"/>
<pop depth="1"/>
</rule>
<rule pattern="\s+">
<token type="TextWhitespace"/>
</rule>
<rule pattern="--.*\n?">
<token type="CommentSingle"/>
</rule>
<rule pattern="/\*">
<token type="CommentMultiline"/>
<push state="sql-multiline-comments"/>
</rule>
<rule pattern="&#39;">
<token type="LiteralStringSingle"/>
<push state="sql-string"/>
</rule>
<rule pattern="&#34;">
<token type="LiteralStringDouble"/>
<push state="sql-double-string"/>
</rule>
<rule pattern="(DATETIME_INTERVAL_PRECISION|PARAMETER_SPECIFIC_CATALOG|PARAMATER_ORDINAL_POSITION|USER_DEFINED_TYPE_CATALOG|PARAMATER_SPECIFIC_SCHEMA|TRANSACTIONS_ROLLED_BACK|USER_DEFINED_TYPE_SCHEMA|PARAMETER_SPECIFIC_NAME|DATETIME_INTERVAL_CODE|TRANSACTIONS_COMMITTED|USER_DEFINED_TYPE_NAME|CHARACTER_SET_CATALOG|DYNAMIC_FUNCTION_CODE|COMMAND_FUNCTION_CODE|RETURNED_OCTET_LENGTH|MESSAGE_OCTET_LENGTH|CHARACTER_SET_SCHEMA|CONSTRAINT_CATALOG|TRANSACTION_ACTIVE|CHARACTER_SET_NAME|CURRENT_TIMESTAMP|CONSTRAINT_SCHEMA|COLLATION_CATALOG|RETURNED_SQLSTATE|DYNAMIC_FUNCTION|CONDITION_NUMBER|CHARACTER_LENGTH|COMMAND_FUNCTION|COLLATION_SCHEMA|CHARACTERISTICS|TRIGGER_CATALOG|CONNECTION_NAME|SUBCLASS_ORIGIN|RETURNED_LENGTH|TIMEZONE_MINUTE|CONSTRAINT_NAME|ROUTINE_CATALOG|TRIGGER_SCHEMA|ROUTINE_SCHEMA|LOCALTIMESTAMP|IMPLEMENTATION|PARAMATER_NAME|MESSAGE_LENGTH|PARAMETER_MODE|COLLATION_NAME|TIMEZONE_HOUR|SPECIFIC_NAME|DETERMINISTIC|CORRESPONTING|AUTHORIZATION|INSTANTIABLE|CURRENT_TIME|CURRENT_USER|ROUTINE_NAME|NOCREATEUSER|MESSAGE_TEXT|SQLEXCEPTION|CATALOG_NAME|SESSION_USER|CLASS_ORIGIN|CURRENT_ROLE|SPECIFICTYPE|SERIALIZABLE|CURRENT_DATE|OCTET_LENGTH|CURRENT_PATH|TRIGGER_NAME|CHAR_LENGTH|SYSTEM_USER|REFERENCING|UNENCRYPTED|COLUMN_NAME|SQLWARNINIG|DIAGNOSTICS|CURSOR_NAME|SERVER_NAME|INSENSITIVE|SCHEMA_NAME|UNCOMMITTED|TRANSACTION|CONSTRUCTOR|LANCOMPILER|CARDINALITY|CONSTRAINTS|TRANSLATION|CHECKPOINT|CONSTRAINT|CONNECTION|PRIVILEGES|COMPLETION|CONVERSION|DELIMITERS|TABLE_NAME|INDITCATOR|INITIALIZE|DESCRIPTOR|REPEATABLE|CREATEUSER|DEFERRABLE|DESTRUCTOR|PROCEDURAL|DICTIONARY|DISCONNECT|TRANSFORMS|KEY_MEMBER|BIT_LENGTH|ASYMMETRIC|ASSIGNMENT|ASENSITIVE|OVERRIDING|PARAMETERS|REFERENCES|ORDINALITY|NOCREATEDB|STATISTICS|DEALLOCATE|SAVE_POINT|RECURSIVE|STRUCTURE|SUBSTRING|IMMEDIATE|GENERATED|SYMMETRIC|STATEMENT|INCREMENT|IMMUTABLE|INCLUDING|COMMITTED|TEMPORARY|INITIALLY|TERMINATE|PRECISION|DELIMITER|TIMESTAMP|INTERSECT|ISOLATION|TRANSFORM|TRANSLATE|ROW_COUNT|ASSERTION|PARAMETER|EXCLUSIVE|LOCALTIME|VALIDATOR|AGGREGATE|EXCLUDING|SENSITIVE|EXCEPTION|ENCRYPTED|OPERATION|HIERARCHY|COLLATION|PROCEDURE|CONTINUE|ENCODING|MINVALUE|SPECIFIC|ABSOLUTE|SECURITY|WHENEVER|EXISTING|VOLATILE|MAXVALUE|EXTERNAL|NULLABLE|VARIABLE|SQLERROR|DISTINCT|DISPATCH|END-EXEC|LOCATION|ALLOCATE|OVERLAPS|UNLISTEN|ROLLBACK|TRUNCATE|DESCRIBE|SQLSTATE|BACKWARD|FUNCTION|LANGUAGE|KEY_TYPE|CASCADED|POSITION|TRAILING|DEFERRED|RELATIVE|DEFAULTS|COALSECE|PREORDER|GROUPING|MODIFIES|INHERITS|PRESERVE|DATABASE|RESTRICT|IDENTITY|TEMPLATE|NATIONAL|CONTAINS|CREATEDB|IMPLICIT|OPERATOR|CONVERT|CURRENT|CONNECT|RECHECK|PRIMARY|STORAGE|DECLARE|DEFAULT|HANDLER|COLLATE|PREPARE|REINDEX|GRANTED|CHECKED|POSTFIX|REPLACE|INSTEAD|CATALOG|RESTART|INVOKER|PLACING|PENDANT|DEFINED|ITERATE|PARTIAL|CASCADE|BREADTH|GENERAL|TRIGGER|SESSION|BETWEEN|DEFINER|LATERAL|LEADING|RETURNS|TRUSTED|UNKNOWN|FORWARD|UNNAMED|OVERLAY|FORTRAN|ANALYZE|OPTIONS|ANALYSE|FOREIGN|ROUTINE|LOCATOR|DESTROY|SUBLIST|VERBOSE|EXTRACT|NOTNULL|EXPLAIN|VERSION|SQLCODE|EXECUTE|NOTHING|DYNAMIC|WITHOUT|SIMILAR|NATURAL|COMMENT|CLUSTER|PASCAL|SOURCE|EQUALS|CALLED|ESCAPE|EXCEPT|SELECT|ISNULL|DOMAIN|SEARCH|SCROLL|SIMPLE|BITVAR|MINUTE|EXISTS|SCHEMA|ATOMIC|METHOD|NOTIFY|ACCESS|UNIQUE|ROLLUP|NULLIF|OBJECT|STABLE|COLUMN|REVOKE|OFFSET|COMMIT|MODIFY|FREEZE|DELETE|RETURN|RESULT|UNNEST|OPTION|GLOBAL|VALUES|RENAME|SYSTEM|STATIC|UPDATE|OUTPUT|LISTEN|STDOUT|STRICT|PUBLIC|IGNORE|PREFIX|SECOND|CREATE|LENGTH|BEFORE|HAVING|INSERT|VACUUM|CURSOR|ELSIF|USING|ALTER|STYPE|CYCLE|LARGE|INPUT|CROSS|INOUT|INNER|INFIX|INDEX|LEVEL|USAGE|ILIKE|VALID|OWNER|GRANT|READS|UPPER|LIMIT|OUTER|STDIN|SYSID|GROUP|ALIAS|ORDER|UNTIL|LOCAL|RESET|START|COUNT|LOWER|TABLE| TEMP|PRIOR|AFTER|STATE|ADMIN|RIGHT|COBOL|FOUND|MATCH|FORCE|ABORT|FIRST|FINAL|CLOSE|DEREF|FETCH|WHERE|FALSE|SCALE|BEGIN|CLASS|TOAST|WRITE|NCLOB|NCHAR|CHECK|CHAIN|SPACE|NAMES|EVERY|MUMPS|CACHE|UNION|UNDER|SETOF|MONTH|SHARE|SCOPE|TREAT|SHOW|SIZE|SOME|SETS|SELF|ELSE|EACH|DROP|TYPE|FROM|RULE|DESC|ROWS|ZONE|ROLE|TRUE|FREE|FULL|GOTO|TRIM|HOLD|HOST|DATA|READ|INTO|USER|JOIN|CUBE|LAST|LEFT|LESS|LIKE|LOAD|LOCK|OPEN|COPY|ONLY|OIDS|VIEW|WHEN|THAN|THEN|NULL|NONE|WITH|WORK|NEXT|YEAR|MODE|CAST|CASE|MOVE|CALL|MORE|BOTH|EXEC|CLOB|OUT|MOD|ARE|SUM|DAY|GET|AVG|NEW|SQL|ABS|MIN|ASC|END|ROW|NOT|FOR|ANY|PLI|MAX|REF|MAP|ADA|KEY|AND|ADD|ALL|OLD|OFF|PAD|SET|OR|ON|TO|IS|OF|IN|IF|GO|AS|DO|AT|NO|BY|C|G)\b">
<token type="Keyword"/>
</rule>
<rule pattern="(CHARACTER|SMALLINT|INTERVAL|DECIMAL|SERIAL8|VARYING|BOOLEAN|VARCHAR|INTEGER|NUMERIC|SERIAL|BINARY|BIGINT|NUMBER|FLOAT|ARRAY|TEXT|REAL|INT8|DATE|CHAR|BLOB|DEC|BIT|INT)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="[+*/&lt;&gt;=~!@#%^&amp;|`?-]">
<token type="Operator"/>
</rule>
<rule pattern="[0-9]+">
<token type="LiteralNumberInteger"/>
</rule>
<rule pattern="[a-z_][\w$]*">
<token type="Name"/>
</rule>
<rule pattern="[;:()\[\],.]">
<token type="Punctuation"/>
</rule>
</state>
<state name="sql-multiline-comments">
<rule pattern="/\*">
<token type="CommentMultiline"/>
<push state="sql-multiline-comments"/>
</rule>
<rule pattern="\*/">
<token type="CommentMultiline"/>
<pop depth="1"/>
</rule>
<rule pattern="[^/*]+">
<token type="CommentMultiline"/>
</rule>
<rule pattern="[/*]">
<token type="CommentMultiline"/>
</rule>
</state>
<state name="sql-string">
<rule pattern="[^&#39;]+">
<token type="LiteralStringSingle"/>
</rule>
<rule pattern="&#39;&#39;">
<token type="LiteralStringSingle"/>
</rule>
<rule pattern="&#39;">
<token type="LiteralStringSingle"/>
<pop depth="1"/>
</rule>
</state>
<state name="sql-double-string">
<rule pattern="[^&#34;]+">
<token type="LiteralStringDouble"/>
</rule>
<rule pattern="&#34;&#34;">
<token type="LiteralStringDouble"/>
</rule>
<rule pattern="&#34;">
<token type="LiteralStringDouble"/>
<pop depth="1"/>
</rule>
</state>
<state name="compile-time-array">
<rule pattern="[^\r\n]*(\r|\n|\r\n)?">
<token type="CommentSpecial"/>
</rule>
</state>
</rules>
</lexer>
+77 -13
View File
@@ -1,3 +1,4 @@
<?xml version="1.0" ?>
<lexer>
<config>
<name>Sed</name>
@@ -10,19 +11,82 @@
</config>
<rules>
<state name="root">
<rule pattern="\s+"><token type="TextWhitespace"/></rule>
<rule pattern="#.*$"><token type="CommentSingle"/></rule>
<rule pattern="[0-9]+"><token type="LiteralNumberInteger"/></rule>
<rule pattern="\$"><token type="Operator"/></rule>
<rule pattern="[{};,!]"><token type="Punctuation"/></rule>
<rule pattern="[dDFgGhHlnNpPqQxz=]"><token type="Keyword"/></rule>
<rule pattern="([berRtTvwW:])([^;\n]*)"><bygroups><token type="Keyword"/><token type="LiteralStringSingle"/></bygroups></rule>
<rule pattern="([aci])((?:.*?\\\n)*(?:.*?[^\\]$))"><bygroups><token type="Keyword"/><token type="LiteralStringDouble"/></bygroups></rule>
<rule pattern="([qQ])([0-9]*)"><bygroups><token type="Keyword"/><token type="LiteralNumberInteger"/></bygroups></rule>
<rule pattern="(/)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(/)"><bygroups><token type="Punctuation"/><token type="LiteralStringRegex"/><token type="Punctuation"/></bygroups></rule>
<rule pattern="(\\(.))((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)"><bygroups><token type="Punctuation"/>None<token type="LiteralStringRegex"/><token type="Punctuation"/></bygroups></rule>
<rule pattern="(y)(.)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)"><bygroups><token type="Keyword"/><token type="Punctuation"/><token type="LiteralStringSingle"/><token type="Punctuation"/><token type="LiteralStringSingle"/><token type="Punctuation"/></bygroups></rule>
<rule pattern="(s)(.)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)((?:[gpeIiMm]|[0-9])*)"><bygroups><token type="Keyword"/><token type="Punctuation"/><token type="LiteralStringRegex"/><token type="Punctuation"/><token type="LiteralStringSingle"/><token type="Punctuation"/><token type="Keyword"/></bygroups></rule>
<rule pattern="\s+">
<token type="TextWhitespace" />
</rule>
<rule pattern="#.*$">
<token type="CommentSingle" />
</rule>
<rule pattern="[0-9]+">
<token type="LiteralNumberInteger" />
</rule>
<rule pattern="\$">
<token type="Operator" />
</rule>
<rule pattern="[{};,!]">
<token type="Punctuation" />
</rule>
<rule pattern="[dDFgGhHlnNpPqQxz=]">
<token type="Keyword" />
</rule>
<rule pattern="([berRtTvwW:])([^;\n]*)">
<bygroups>
<token type="Keyword" />
<token type="LiteralStringSingle" />
</bygroups>
</rule>
<rule pattern="([aci])((?:.*?\\\n)*(?:.*?[^\\]$))">
<bygroups>
<token type="Keyword" />
<token type="LiteralStringDouble" />
</bygroups>
</rule>
<rule pattern="([qQ])([0-9]*)">
<bygroups>
<token type="Keyword" />
<token type="LiteralNumberInteger" />
</bygroups>
</rule>
<rule pattern="(/)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(/)">
<bygroups>
<token type="Punctuation" />
<token type="LiteralStringRegex" />
<token type="Punctuation" />
</bygroups>
</rule>
<rule pattern="(\\(.))((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)">
<bygroups>
<token type="Punctuation" />
<token type="Text" />
<token type="LiteralStringRegex" />
<token type="Punctuation" />
</bygroups>
</rule>
<rule
pattern="(y)(.)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)"
>
<bygroups>
<token type="Keyword" />
<token type="Punctuation" />
<token type="LiteralStringSingle" />
<token type="Punctuation" />
<token type="LiteralStringSingle" />
<token type="Punctuation" />
</bygroups>
</rule>
<rule
pattern="(s)(.)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)((?:(?:\\[^\n]|[^\\])*?\\\n)*?(?:\\.|[^\\])*?)(\2)((?:[gpeIiMm]|[0-9])*)"
>
<bygroups>
<token type="Keyword" />
<token type="Punctuation" />
<token type="LiteralStringRegex" />
<token type="Punctuation" />
<token type="LiteralStringSingle" />
<token type="Punctuation" />
<token type="Keyword" />
</bygroups>
</rule>
</state>
</rules>
</lexer>
@@ -157,8 +157,20 @@
<rule pattern="(continue|returns|storage|memory|delete|return|throw|break|catch|while|else|from|new|try|for|if|is|as|do|in|_)\b">
<token type="Keyword"/>
</rule>
<rule pattern="assembly\b">
<token type="Keyword"/>
<rule pattern="(assembly)(\s+\()(.+)(\)\s+{)">
<bygroups>
<token type="Keyword"/>
<token type="Text"/>
<token type="LiteralString"/>
<token type="Text"/>
</bygroups>
<push state="assembly"/>
</rule>
<rule pattern="(assembly)(\s+{)">
<bygroups>
<token type="Keyword"/>
<token type="Text"/>
</bygroups>
<push state="assembly"/>
</rule>
<rule pattern="(contract|interface|enum|event|struct)(\s+)([a-zA-Z_]\w*)">
@@ -235,7 +247,7 @@
<token type="Punctuation"/>
<pop depth="1"/>
</rule>
<rule pattern="[(),]">
<rule pattern="[(),.]">
<token type="Punctuation"/>
</rule>
<rule pattern=":=|=:">
@@ -276,4 +288,4 @@
</rule>
</state>
</rules>
</lexer>
</lexer>
+106 -97
View File
@@ -3,138 +3,147 @@
<name>Terraform</name>
<alias>terraform</alias>
<alias>tf</alias>
<alias>hcl</alias>
<filename>*.tf</filename>
<filename>*.hcl</filename>
<mime_type>application/x-tf</mime_type>
<mime_type>application/x-terraform</mime_type>
</config>
<rules>
<state name="string">
<rule pattern="&#34;">
<token type="LiteralStringDouble"/>
<pop depth="1"/>
</rule>
<rule pattern="\\\\">
<token type="LiteralStringDouble"/>
<token type="LiteralStringDouble" />
<pop depth="1" />
</rule>
<rule pattern="\\\\&#34;">
<token type="LiteralStringDouble"/>
</rule>
<rule pattern="\$\{">
<token type="LiteralStringInterpol"/>
<push state="interp-inside"/>
</rule>
<rule pattern="\$">
<token type="LiteralStringDouble"/>
<token type="LiteralStringDouble" />
</rule>
<rule pattern="[^&#34;\\\\$]+">
<token type="LiteralStringDouble"/>
<token type="LiteralStringDouble" />
</rule>
<rule pattern="[^\\\\&#34;$]+">
<token type="LiteralStringDouble" />
</rule>
<rule pattern="\$\{">
<token type="LiteralStringInterpol" />
<push state="interp-inside" />
</rule>
</state>
<state name="interp-inside">
<rule pattern="\}">
<token type="LiteralStringInterpol"/>
<pop depth="1"/>
<token type="LiteralStringInterpol" />
<pop depth="1" />
</rule>
<rule>
<include state="root"/>
<include state="root" />
</rule>
</state>
<state name="root">
<rule pattern="[\[\](),.{}]">
<token type="Punctuation"/>
</rule>
<rule pattern="-?[0-9]+">
<token type="LiteralNumber"/>
</rule>
<rule pattern="=&gt;">
<token type="Punctuation"/>
</rule>
<rule pattern="(false|true)\b">
<token type="KeywordConstant"/>
</rule>
<rule pattern="/(?s)\*(((?!\*/).)*)\*/">
<token type="CommentMultiline"/>
</rule>
<rule pattern="\s*(#|//).*\n">
<token type="CommentSingle"/>
</rule>
<rule pattern="([a-zA-Z]\w*)(\s*)(=(?!&gt;))">
<bygroups>
<token type="NameAttribute"/>
<token type="Text"/>
<token type="Text"/>
</bygroups>
</rule>
<rule pattern="^\s*(provisioner|variable|resource|provider|module|output|data)\b">
<token type="KeywordReserved"/>
</rule>
<rule pattern="(for|in)\b">
<token type="Keyword"/>
</rule>
<rule pattern="(module|count|data|each|var)">
<token type="NameBuiltin"/>
</rule>
<rule pattern="(parseint|signum|floor|ceil|log|max|min|abs|pow)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="(trimsuffix|formatlist|trimprefix|trimspace|regexall|replace|indent|strrev|format|substr|chomp|split|title|regex|lower|upper|trim|join)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="[^.](setintersection|coalescelist|setsubtract|setproduct|matchkeys|chunklist|transpose|contains|distinct|coalesce|setunion|reverse|flatten|element|compact|lookup|length|concat|values|zipmap|range|merge|slice|index|list|sort|keys|map)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="[^.](base64decode|base64encode|base64gzip|jsondecode|jsonencode|yamldecode|yamlencode|csvdecode|urlencode)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="(templatefile|filebase64|fileexists|pathexpand|basename|abspath|fileset|dirname|file)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="(formatdate|timestamp|timeadd)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="(filebase64sha256|filebase64sha512|base64sha512|base64sha256|filesha256|rsadecrypt|filesha512|filesha1|filemd5|uuidv5|bcrypt|sha256|sha512|sha1|uuid|md5)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="(cidrnetmask|cidrsubnet|cidrhost)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="(tostring|tonumber|tobool|tolist|tomap|toset|can|try)\b">
<token type="NameBuiltin"/>
</rule>
<rule pattern="=(?!&gt;)|\+|-|\*|\/|:|!|%|&gt;|&lt;(?!&lt;)|&gt;=|&lt;=|==|!=|&amp;&amp;|\||\?">
<token type="Operator"/>
</rule>
<rule pattern="\n|\s+|\\\n">
<token type="Text"/>
</rule>
<rule pattern="[a-zA-Z]\w*">
<token type="NameOther"/>
<token type="Punctuation" />
</rule>
<rule pattern="&#34;">
<token type="LiteralStringDouble"/>
<push state="string"/>
<token type="LiteralStringDouble" />
<push state="string" />
</rule>
<rule pattern="-?[0-9]+">
<token type="LiteralNumber" />
</rule>
<rule pattern="=&gt;">
<token type="Punctuation" />
</rule>
<rule pattern="(false|true)\b">
<token type="KeywordConstant" />
</rule>
<rule pattern="/(?s)\*(((?!\*/).)*)\*/">
<token type="CommentMultiline" />
</rule>
<rule pattern="\s*(#|//).*\n">
<token type="CommentSingle" />
</rule>
<rule pattern="(?!\s*)(variable)(\s*)">
<bygroups>
<token type="Name" />
<token type="Text" />
</bygroups>
</rule>
<rule pattern="^(provisioner|variable|resource|provider|module|output|data)(?!\.)\b">
<token type="KeywordReserved" />
</rule>
<rule pattern="(for|in)\b">
<token type="Keyword" />
</rule>
<rule pattern="(module|count|data|each|var)\b">
<token type="NameBuiltin" />
</rule>
<rule pattern="(parseint|signum|floor|ceil|log|max|min|abs|pow)\b">
<token type="NameBuiltin" />
</rule>
<rule
pattern="(trimsuffix|formatlist|trimprefix|trimspace|regexall|replace|indent|strrev|format|substr|chomp|split|title|regex|lower|upper|trim|join)\b"
>
<token type="NameBuiltin" />
</rule>
<rule
pattern="[^.](setintersection|coalescelist|setsubtract|setproduct|matchkeys|chunklist|transpose|contains|distinct|coalesce|setunion|reverse|flatten|element|compact|lookup|length|concat|values|zipmap|range|merge|slice|index|list|sort|keys|map)\b"
>
<token type="NameBuiltin" />
</rule>
<rule
pattern="[^.](base64decode|base64encode|base64gzip|jsondecode|jsonencode|yamldecode|yamlencode|csvdecode|urlencode)\b"
>
<token type="NameBuiltin" />
</rule>
<rule pattern="(templatefile|filebase64|fileexists|pathexpand|basename|abspath|fileset|dirname|file)\b">
<token type="NameBuiltin" />
</rule>
<rule pattern="(formatdate|timestamp|timeadd)\b">
<token type="NameBuiltin" />
</rule>
<rule
pattern="(filebase64sha256|filebase64sha512|base64sha512|base64sha256|filesha256|rsadecrypt|filesha512|filesha1|filemd5|uuidv5|bcrypt|sha256|sha512|sha1|uuid|md5)\b"
>
<token type="NameBuiltin" />
</rule>
<rule pattern="(cidrnetmask|cidrsubnet|cidrhost)\b">
<token type="NameBuiltin" />
</rule>
<rule pattern="(tostring|tonumber|tobool|tolist|tomap|toset|can|try)\b">
<token type="NameBuiltin" />
</rule>
<rule pattern="(^|[^.\w])(name|x|default|type|description|value)(_[a-zA-Z]\w*)*">
<token type="NameAttribute" />
</rule>
<rule pattern="=(?!&gt;)|\+|-|\*|\/|:|!|%|&gt;|&lt;(?!&lt;)|&gt;=|&lt;=|==|!=|&amp;&amp;|\||\?">
<token type="Operator" />
</rule>
<rule pattern="\n|\s+|\\\n">
<token type="Text" />
</rule>
<rule pattern="[a-zA-Z]\w*">
<token type="NameOther" />
</rule>
<rule pattern="(?s)(&lt;&lt;-?)(\w+)(\n\s*(?:(?!\2).)*\s*\n\s*)(\2)">
<bygroups>
<token type="Operator"/>
<token type="Operator"/>
<token type="LiteralString"/>
<token type="Operator"/>
<token type="Operator" />
<token type="Operator" />
<token type="LiteralString" />
<token type="Operator" />
</bygroups>
</rule>
</state>
<state name="declaration">
<rule pattern="(\s*)(&#34;(?:\\\\|\\&#34;|[^&#34;])*&#34;)(\s*)">
<bygroups>
<token type="Text"/>
<token type="NameVariable"/>
<token type="Text"/>
<token type="Text" />
<token type="NameAttribute" />
<token type="Text" />
</bygroups>
</rule>
<rule pattern="\{">
<token type="Punctuation"/>
<pop depth="1"/>
<token type="Punctuation" />
<pop depth="1" />
</rule>
</state>
</rules>
</lexer>
</lexer>
@@ -5,6 +5,7 @@
<filename>*.toml</filename>
<filename>Pipfile</filename>
<filename>poetry.lock</filename>
<filename>uv.lock</filename>
<mime_type>text/x-toml</mime_type>
</config>
<rules>
+118 -111
View File
@@ -15,280 +15,287 @@
<rules>
<state name="expression">
<rule pattern="{">
<token type="Punctuation"/>
<push/>
<token type="Punctuation" />
<push />
</rule>
<rule pattern="}">
<token type="Punctuation"/>
<pop depth="1"/>
<token type="Punctuation" />
<pop depth="1" />
</rule>
<rule>
<include state="root"/>
<include state="root" />
</rule>
</state>
<state name="jsx">
<rule pattern="(&lt;)(/?)(&gt;)">
<bygroups>
<token type="Punctuation"/>
<token type="Punctuation"/>
<token type="Punctuation"/>
<token type="Punctuation" />
<token type="Punctuation" />
<token type="Punctuation" />
</bygroups>
</rule>
<rule pattern="(&lt;)([\w\.]+)">
<bygroups>
<token type="Punctuation"/>
<token type="NameTag"/>
<token type="Punctuation" />
<token type="NameTag" />
</bygroups>
<push state="tag"/>
<push state="tag" />
</rule>
<rule pattern="(&lt;)(/)([\w\.]*)(&gt;)">
<bygroups>
<token type="Punctuation"/>
<token type="Punctuation"/>
<token type="NameTag"/>
<token type="Punctuation"/>
<token type="Punctuation" />
<token type="Punctuation" />
<token type="NameTag" />
<token type="Punctuation" />
</bygroups>
</rule>
</state>
<state name="tag">
<rule>
<include state="jsx"/>
<include state="jsx" />
</rule>
<rule pattern=",">
<token type="Punctuation"/>
<token type="Punctuation" />
</rule>
<rule pattern="&#34;(\\\\|\\&#34;|[^&#34;])*&#34;">
<token type="LiteralStringDouble"/>
<token type="LiteralStringDouble" />
</rule>
<rule pattern="&#39;(\\\\|\\&#39;|[^&#39;])*&#39;">
<token type="LiteralStringSingle"/>
<token type="LiteralStringSingle" />
</rule>
<rule pattern="`">
<token type="LiteralStringBacktick"/>
<push state="interp"/>
<token type="LiteralStringBacktick" />
<push state="interp" />
</rule>
<rule>
<include state="commentsandwhitespace"/>
<include state="commentsandwhitespace" />
</rule>
<rule pattern="\s+">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="([\w-]+\s*)(=)(\s*)">
<bygroups>
<token type="NameAttribute"/>
<token type="Operator"/>
<token type="Text"/>
<token type="NameAttribute" />
<token type="Operator" />
<token type="Text" />
</bygroups>
<push state="attr"/>
<push state="attr" />
</rule>
<rule pattern="[{}]+">
<token type="Punctuation"/>
<token type="Punctuation" />
</rule>
<rule pattern="[\w\.]+">
<token type="NameAttribute"/>
<token type="NameAttribute" />
</rule>
<rule pattern="(/?)(\s*)(&gt;)">
<bygroups>
<token type="Punctuation"/>
<token type="Text"/>
<token type="Punctuation"/>
<token type="Punctuation" />
<token type="Text" />
<token type="Punctuation" />
</bygroups>
<pop depth="1"/>
<pop depth="1" />
</rule>
</state>
<state name="comment">
<rule pattern="[^-]+">
<token type="Comment"/>
<token type="Comment" />
</rule>
<rule pattern="--&gt;">
<token type="Comment"/>
<pop depth="1"/>
<token type="Comment" />
<pop depth="1" />
</rule>
<rule pattern="-">
<token type="Comment"/>
<token type="Comment" />
</rule>
</state>
<state name="commentsandwhitespace">
<rule pattern="\s+">
<token type="Text"/>
<token type="Text" />
</rule>
<rule pattern="&lt;!--">
<token type="Comment"/>
<push state="comment"/>
<token type="Comment" />
<push state="comment" />
</rule>
<rule pattern="//.*?\n">
<token type="CommentSingle"/>
<token type="CommentSingle" />
</rule>
<rule pattern="/\*.*?\*/">
<token type="CommentMultiline"/>
<token type="CommentMultiline" />
</rule>
</state>
<state name="badregex">
<rule pattern="\n">
<token type="Text"/>
<pop depth="1"/>
<token type="Text" />
<pop depth="1" />
</rule>
</state>
<state name="interp">
<rule pattern="`">
<token type="LiteralStringBacktick"/>
<pop depth="1"/>
<token type="LiteralStringBacktick" />
<pop depth="1" />
</rule>
<rule pattern="\\\\">
<token type="LiteralStringBacktick"/>
<token type="LiteralStringBacktick" />
</rule>
<rule pattern="\\`">
<token type="LiteralStringBacktick"/>
<token type="LiteralStringBacktick" />
</rule>
<rule pattern="\$\{">
<token type="LiteralStringInterpol"/>
<push state="interp-inside"/>
<token type="LiteralStringInterpol" />
<push state="interp-inside" />
</rule>
<rule pattern="\$">
<token type="LiteralStringBacktick"/>
<token type="LiteralStringBacktick" />
</rule>
<rule pattern="[^`\\$]+">
<token type="LiteralStringBacktick"/>
<token type="LiteralStringBacktick" />
</rule>
</state>
<state name="attr">
<rule pattern="{">
<token type="Punctuation"/>
<push state="expression"/>
<token type="Punctuation" />
<push state="expression" />
</rule>
<rule pattern="&#34;.*?&#34;">
<token type="LiteralString"/>
<pop depth="1"/>
<token type="LiteralString" />
<pop depth="1" />
</rule>
<rule pattern="&#39;.*?&#39;">
<token type="LiteralString"/>
<pop depth="1"/>
<token type="LiteralString" />
<pop depth="1" />
</rule>
<rule>
<pop depth="1"/>
<pop depth="1" />
</rule>
</state>
<state name="interp-inside">
<rule pattern="\}">
<token type="LiteralStringInterpol"/>
<pop depth="1"/>
<token type="LiteralStringInterpol" />
<pop depth="1" />
</rule>
<rule>
<include state="root"/>
<include state="root" />
</rule>
</state>
<state name="slashstartsregex">
<rule>
<include state="commentsandwhitespace"/>
<include state="commentsandwhitespace" />
</rule>
<rule pattern="/(\\.|[^[/\\\n]|\[(\\.|[^\]\\\n])*])+/([gim]+\b|\B)">
<token type="LiteralStringRegex"/>
<pop depth="1"/>
<token type="LiteralStringRegex" />
<pop depth="1" />
</rule>
<rule pattern="(?=/)">
<token type="Text"/>
<push state="badregex"/>
<token type="Text" />
<push state="badregex" />
</rule>
<rule>
<pop depth="1"/>
<pop depth="1" />
</rule>
</state>
<state name="root">
<rule>
<include state="jsx"/>
<include state="jsx" />
</rule>
<rule pattern="^(?=\s|/|&lt;!--)">
<token type="Text"/>
<push state="slashstartsregex"/>
<token type="Text" />
<push state="slashstartsregex" />
</rule>
<rule>
<include state="commentsandwhitespace"/>
<include state="commentsandwhitespace" />
</rule>
<rule pattern="\+\+|--|~|&amp;&amp;|\?|:|\|\||\\(?=\n)|(&lt;&lt;|&gt;&gt;&gt;?|==?|!=?|[-&lt;&gt;+*%&amp;|^/])=?">
<token type="Operator"/>
<push state="slashstartsregex"/>
<token type="Operator" />
<push state="slashstartsregex" />
</rule>
<rule pattern="[{(\[;,]">
<token type="Punctuation"/>
<push state="slashstartsregex"/>
<token type="Punctuation" />
<push state="slashstartsregex" />
</rule>
<rule pattern="[})\].]">
<token type="Punctuation"/>
<token type="Punctuation" />
</rule>
<rule pattern="(for|in|of|while|do|break|return|yield|continue|switch|case|default|if|else|throw|try|catch|finally|new|delete|typeof|instanceof|keyof|asserts|is|infer|await|void|this)\b">
<token type="Keyword"/>
<push state="slashstartsregex"/>
<rule
pattern="(for|in|of|while|do|break|return|yield|continue|switch|case|default|if|else|throw|try|catch|finally|new|delete|typeof|instanceof|keyof|asserts|is|infer|await|void|this)\b"
>
<token type="Keyword" />
<push state="slashstartsregex" />
</rule>
<rule pattern="(var|let|with|function)\b">
<token type="KeywordDeclaration"/>
<push state="slashstartsregex"/>
<token type="KeywordDeclaration" />
<push state="slashstartsregex" />
</rule>
<rule pattern="(abstract|async|boolean|class|const|debugger|enum|export|extends|from|get|global|goto|implements|import|interface|namespace|package|private|protected|public|readonly|require|set|static|super|type)\b">
<token type="KeywordReserved"/>
<rule
pattern="(abstract|async|boolean|class|const|debugger|enum|export|extends|from|get|global|goto|implements|import|interface|namespace|package|private|protected|public|readonly|require|set|static|super|type)\b"
>
<token type="KeywordReserved" />
</rule>
<rule pattern="(true|false|null|NaN|Infinity|undefined)\b">
<token type="KeywordConstant"/>
<token type="KeywordConstant" />
</rule>
<rule pattern="(Array|Boolean|Date|Error|Function|Math|Number|Object|Packages|RegExp|String|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt|document|this|window)\b">
<token type="NameBuiltin"/>
<rule
pattern="(Array|Boolean|Date|Error|Function|Math|Number|Object|Packages|RegExp|String|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt|document|this|window)\b"
>
<token type="NameBuiltin" />
</rule>
<rule pattern="\b(module)(\s+)(&quot;[\w\./@]+&quot;)(\s+)">
<bygroups>
<token type="KeywordReserved"/>
<token type="Text"/>
<token type="NameOther"/>
<token type="Text"/>
<token type="KeywordReserved" />
<token type="Text" />
<token type="NameOther" />
<token type="Text" />
</bygroups>
<push state="slashstartsregex"/>
<push state="slashstartsregex" />
</rule>
<rule pattern="\b(string|bool|number|any|never|object|symbol|unique|unknown|bigint)\b">
<token type="KeywordType"/>
<token type="KeywordType" />
</rule>
<rule pattern="\b(constructor|declare|interface|as)\b">
<token type="KeywordReserved"/>
<token type="KeywordReserved" />
</rule>
<rule pattern="(super)(\s*)(\([\w,?.$\s]+\s*\))">
<bygroups>
<token type="KeywordReserved"/>
<token type="Text"/>
<token type="KeywordReserved" />
<token type="TextWhitespace" />
<token type="Text" />
</bygroups>
<push state="slashstartsregex"/>
<push state="slashstartsregex" />
</rule>
<rule pattern="([a-zA-Z_?.$][\w?.$]*)\(\) \{">
<token type="NameOther"/>
<push state="slashstartsregex"/>
<token type="NameOther" />
<push state="slashstartsregex" />
</rule>
<rule pattern="([\w?.$][\w?.$]*)(\s*:\s*)([\w?.$][\w?.$]*)">
<bygroups>
<token type="NameOther"/>
<token type="Text"/>
<token type="KeywordType"/>
<token type="NameOther" />
<token type="Text" />
<token type="KeywordType" />
</bygroups>
</rule>
<rule pattern="[$a-zA-Z_]\w*">
<token type="NameOther"/>
<token type="NameOther" />
</rule>
<rule pattern="[0-9][0-9]*\.[0-9]+([eE][0-9]+)?[fd]?">
<token type="LiteralNumberFloat"/>
<token type="LiteralNumberFloat" />
</rule>
<rule pattern="0x[0-9a-fA-F]+">
<token type="LiteralNumberHex"/>
<token type="LiteralNumberHex" />
</rule>
<rule pattern="[0-9]+">
<token type="LiteralNumberInteger"/>
<token type="LiteralNumberInteger" />
</rule>
<rule pattern="&#34;(\\\\|\\&#34;|[^&#34;])*&#34;">
<token type="LiteralStringDouble"/>
<token type="LiteralStringDouble" />
</rule>
<rule pattern="&#39;(\\\\|\\&#39;|[^&#39;])*&#39;">
<token type="LiteralStringSingle"/>
<token type="LiteralStringSingle" />
</rule>
<rule pattern="`">
<token type="LiteralStringBacktick"/>
<push state="interp"/>
<token type="LiteralStringBacktick" />
<push state="interp" />
</rule>
<rule pattern="@\w+">
<token type="KeywordDeclaration"/>
<token type="KeywordDeclaration" />
</rule>
</state>
</rules>
+13 -25
View File
@@ -64,25 +64,13 @@
<rule pattern="(-)([\w]+)">
<token type="NameTag"/>
</rule>
<rule pattern="(@[\w]+)(=&#34;[\S]+&#34;)(&gt;)">
<rule pattern="(@[\w.]+)(=&#34;.*?&#34;)?(\/?&gt;|\s)">
<bygroups>
<token type="NameTag"/>
<token type="LiteralString"/>
<token type="Punctuation"/>
</bygroups>
</rule>
<rule pattern="(@[\w]+)(=&#34;[\S]+&#34;)">
<bygroups>
<token type="NameTag"/>
<token type="LiteralString"/>
</bygroups>
</rule>
<rule pattern="(@[\S]+)(=&#34;[\S]+&#34;)">
<bygroups>
<token type="NameTag"/>
<token type="LiteralString"/>
</bygroups>
</rule>
<rule pattern="(:[\S]+)(=)(&#34;[\S]+&#34;)">
<bygroups>
<token type="NameTag"/>
@@ -96,16 +84,7 @@
<rule pattern="(v-b-[\S]+)">
<token type="NameTag"/>
</rule>
<rule pattern="(v-[\w]+)(=&#34;.+)([:][\w]+)(=&#34;[\w]+&#34;)(&gt;)">
<bygroups>
<token type="NameTag"/>
<token type="LiteralString"/>
<token type="NameTag"/>
<token type="LiteralString"/>
<token type="Punctuation"/>
</bygroups>
</rule>
<rule pattern="(v-[\w]+)(=)(&#34;[\S ]+&#34;)(&gt;|\s)">
<rule pattern="(v-[\w-]+)(=)(&#34;[\S ]+&#34;)(\/?&gt;|\s)">
<bygroups>
<token type="NameTag"/>
<token type="Operator"/>
@@ -113,19 +92,28 @@
<token type="Punctuation"/>
</bygroups>
</rule>
<rule pattern="(v-[\w]+)(&gt;)">
<rule pattern="(v-[\w-]+)(\/?&gt;|\s)">
<bygroups>
<token type="NameTag"/>
<token type="Punctuation"/>
</bygroups>
</rule>
<rule pattern="(v-[\w]+)(=&#34;.+&#34;)(&gt;)">
<rule pattern="(v-[\w-]+)(=&#34;.+&#34;)(\/?&gt;|\s)">
<bygroups>
<token type="NameTag"/>
<token type="LiteralString"/>
<token type="Punctuation"/>
</bygroups>
</rule>
<rule pattern="(v-[\w-]+)(=&#34;.+)([:][\w]+)(=&#34;[\w]+&#34;)(\/?&gt;|\s)">
<bygroups>
<token type="NameTag"/>
<token type="LiteralString"/>
<token type="NameTag"/>
<token type="LiteralString"/>
<token type="Punctuation"/>
</bygroups>
</rule>
<rule pattern="(&lt;)([\w]+)">
<bygroups>
<token type="Punctuation"/>
@@ -3,6 +3,7 @@
<name>Zig</name>
<alias>zig</alias>
<filename>*.zig</filename>
<filename>*.zon</filename>
<mime_type>text/zig</mime_type>
</config>
<rules>
@@ -76,6 +77,9 @@
<rule pattern="(?:_?[0-9])+">
<token type="LiteralNumberInteger"/>
</rule>
<rule pattern="\b[A-Za-z_]\w*(?=\s*\()">
<token type="NameFunction"/>
</rule>
<rule pattern="@[a-zA-Z_]\w*">
<token type="NameBuiltin"/>
</rule>
+37
View File
@@ -0,0 +1,37 @@
package lexers
import (
. "github.com/alecthomas/chroma/v2" // nolint
)
// Gemtext lexer.
var Gemtext = Register(MustNewLexer(
&Config{
Name: "Gemtext",
Aliases: []string{"gemtext", "gmi", "gmni", "gemini"},
Filenames: []string{"*.gmi", "*.gmni", "*.gemini"},
MimeTypes: []string{"text/gemini"},
},
gemtextRules,
))
func gemtextRules() Rules {
return Rules{
"root": {
{`^(#[^#].+\r?\n)`, ByGroups(GenericHeading), nil},
{`^(#{2,3}.+\r?\n)`, ByGroups(GenericSubheading), nil},
{`^(\* )(.+\r?\n)`, ByGroups(Keyword, Text), nil},
{`^(>)(.+\r?\n)`, ByGroups(Keyword, GenericEmph), nil},
{"^(```\\r?\\n)([\\w\\W]*?)(^```)(.+\\r?\\n)?", ByGroups(String, Text, String, Comment), nil},
{
"^(```)(\\w+)(\\r?\\n)([\\w\\W]*?)(^```)(.+\\r?\\n)?",
UsingByGroup(2, 4, String, String, String, Text, String, Comment),
nil,
},
{"^(```)(.+\\r?\\n)([\\w\\W]*?)(^```)(.+\\r?\\n)?", ByGroups(String, String, Text, String, Comment), nil},
{`^(=>)(\s*)([^\s]+)(\s*)$`, ByGroups(Keyword, Text, NameAttribute, Text), nil},
{`^(=>)(\s*)([^\s]+)(\s+)(.+)$`, ByGroups(Keyword, Text, NameAttribute, Text, NameTag), nil},
{`(.|(?:\r?\n))`, ByGroups(Text), nil},
},
}
}
+4 -4
View File
@@ -28,10 +28,10 @@ var Go = Register(MustNewLexer(
func goRules() Rules {
return Rules{
"root": {
{`\n`, Text, nil},
{`\s+`, Text, nil},
{`\\\n`, Text, nil},
{`//[^\n\r]*`, CommentSingle, nil},
{`\n`, TextWhitespace, nil},
{`\s+`, TextWhitespace, nil},
{`//[^\s][^\n\r]*`, CommentPreproc, nil},
{`//\s+[^\n\r]*`, CommentSingle, nil},
{`/(\\\n)?[*](.|\n)*?[*](\\\n)?/`, CommentMultiline, nil},
{`(import|package)\b`, KeywordNamespace, nil},
{`(var|func|struct|map|chan|type|interface|const)\b`, KeywordDeclaration, nil},
+6
View File
@@ -29,6 +29,12 @@ func Names(withAliases bool) []string {
return GlobalLexerRegistry.Names(withAliases)
}
// Aliases of all the lexers, and skip those lexers who do not have any aliases,
// or show their name instead
func Aliases(skipWithoutAliases bool) []string {
return GlobalLexerRegistry.Aliases(skipWithoutAliases)
}
// Get a Lexer by name, alias or file extension.
//
// Note that this if there isn't an exact match on name or alias, this will
+3 -3
View File
@@ -5,7 +5,7 @@ import (
)
// Markdown lexer.
var Markdown = Register(DelegatingLexer(HTML, MustNewLexer(
var Markdown = Register(MustNewLexer(
&Config{
Name: "markdown",
Aliases: []string{"md", "mkd"},
@@ -13,7 +13,7 @@ var Markdown = Register(DelegatingLexer(HTML, MustNewLexer(
MimeTypes: []string{"text/x-markdown"},
},
markdownRules,
)))
))
func markdownRules() Rules {
return Rules{
@@ -40,7 +40,7 @@ func markdownRules() Rules {
{"`[^`]+`", LiteralStringBacktick, nil},
{`[@#][\w/:]+`, NameEntity, nil},
{`(!?\[)([^]]+)(\])(\()([^)]+)(\))`, ByGroups(Text, NameTag, Text, Text, NameAttribute, Text), nil},
{`.|\n`, Other, nil},
{`.|\n`, Text, nil},
},
}
}
+8 -17
View File
@@ -2,6 +2,7 @@ package lexers
import (
"regexp"
"slices"
"strings"
"unicode/utf8"
@@ -1318,21 +1319,11 @@ func indexAt(str []rune, substr []rune, pos int) int {
return idx
}
// Tells if an array of string contains a string
func contains(s []string, e string) bool {
for _, value := range s {
if value == e {
return true
}
}
return false
}
type rulePosition int
const (
topRule rulePosition = 0
bottomRule = -1
topRule rulePosition = 0 - iota
bottomRule
)
type ruleMakingConfig struct {
@@ -1625,15 +1616,15 @@ func quote(groups []string, state *LexerState) Iterator {
var tokenState string
switch {
case keyword == "qq" || contains(tokenStates, "qq"):
case keyword == "qq" || slices.Contains(tokenStates, "qq"):
tokenState = "qq"
case adverbsStr == "ww" || contains(tokenStates, "ww"):
case adverbsStr == "ww" || slices.Contains(tokenStates, "ww"):
tokenState = "ww"
case contains(tokenStates, "Q-closure") && contains(tokenStates, "Q-variable"):
case slices.Contains(tokenStates, "Q-closure") && slices.Contains(tokenStates, "Q-variable"):
tokenState = "qq"
case contains(tokenStates, "Q-closure"):
case slices.Contains(tokenStates, "Q-closure"):
tokenState = "Q-closure"
case contains(tokenStates, "Q-variable"):
case slices.Contains(tokenStates, "Q-variable"):
tokenState = "Q-variable"
default:
tokenState = "Q"
+482 -199
View File
@@ -1,322 +1,605 @@
Generated with:
g 'class.*RegexLexer' | pawk --strict -F: '"pygments.lexers.%s.%s" % (f[0].split(".")[0], f[2].split()[1].split("(")[0])' > lexers.txt
import pygments.lexers # v2.19.1
for x in pygments.lexers.get_all_lexers(plugins=False):
if len(x[1]):
lexer = pygments.lexers.get_lexer_by_name(x[1][0])
print(f"{lexer.__module__}.{lexer.__class__.__name__}")
kotlin:
invalid unicode escape sequences
FIXED: Have to disable wide Unicode characters in unistring.py
pygments.lexers.ambient.AmbientTalkLexer
pygments.lexers.ampl.AmplLexer
pygments.lexers.actionscript.ActionScriptLexer
pygments.lexers.actionscript.ActionScript3Lexer
pygments.lexers.actionscript.ActionScriptLexer
pygments.lexers.actionscript.MxmlLexer
pygments.lexers.ada.AdaLexer
pygments.lexers.algebra.BCLexer
pygments.lexers.algebra.GAPConsoleLexer
pygments.lexers.algebra.GAPLexer
pygments.lexers.algebra.MathematicaLexer
pygments.lexers.algebra.MuPADLexer
pygments.lexers.algebra.BCLexer
pygments.lexers.ambient.AmbientTalkLexer
pygments.lexers.amdgpu.AMDGPULexer
pygments.lexers.ampl.AmplLexer
pygments.lexers.apdlexer.apdlexer
pygments.lexers.apl.APLLexer
pygments.lexers.bibtex.BibTeXLexer
pygments.lexers.bibtex.BSTLexer
pygments.lexers.basic.BlitzMaxLexer
pygments.lexers.basic.BlitzBasicLexer
pygments.lexers.basic.MonkeyLexer
pygments.lexers.basic.CbmBasicV2Lexer
pygments.lexers.basic.QBasicLexer
pygments.lexers.automation.AutohotkeyLexer
pygments.lexers.automation.AutoItLexer
pygments.lexers.archetype.AtomsLexer
pygments.lexers.c_like.ClayLexer
pygments.lexers.c_like.ValaLexer
pygments.lexers.archetype.AdlLexer
pygments.lexers.archetype.CadlLexer
pygments.lexers.archetype.OdinLexer
pygments.lexers.arrow.ArrowLexer
pygments.lexers.arturo.ArturoLexer
pygments.lexers.asc.AscLexer
pygments.lexers.asm.Ca65Lexer
pygments.lexers.asm.CObjdumpLexer
pygments.lexers.asm.CppObjdumpLexer
pygments.lexers.asm.Dasm16Lexer
pygments.lexers.asm.DObjdumpLexer
pygments.lexers.asm.GasLexer
pygments.lexers.asm.ObjdumpLexer
pygments.lexers.asm.HsailLexer
pygments.lexers.asm.LlvmLexer
pygments.lexers.asm.LlvmMirBodyLexer
pygments.lexers.asm.LlvmMirLexer
pygments.lexers.asm.NasmLexer
pygments.lexers.asm.NasmObjdumpLexer
pygments.lexers.asm.ObjdumpLexer
pygments.lexers.asm.TasmLexer
pygments.lexers.asm.Ca65Lexer
pygments.lexers.business.CobolLexer
pygments.lexers.asn1.Asn1Lexer
pygments.lexers.automation.AutohotkeyLexer
pygments.lexers.automation.AutoItLexer
pygments.lexers.bare.BareLexer
pygments.lexers.basic.BBCBasicLexer
pygments.lexers.basic.BlitzBasicLexer
pygments.lexers.basic.BlitzMaxLexer
pygments.lexers.basic.CbmBasicV2Lexer
pygments.lexers.basic.MonkeyLexer
pygments.lexers.basic.QBasicLexer
pygments.lexers.basic.VBScriptLexer
pygments.lexers.bdd.BddLexer
pygments.lexers.berry.BerryLexer
pygments.lexers.bibtex.BibTeXLexer
pygments.lexers.bibtex.BSTLexer
pygments.lexers.blueprint.BlueprintLexer
pygments.lexers.boa.BoaLexer
pygments.lexers.bqn.BQNLexer
pygments.lexers.business.ABAPLexer
pygments.lexers.business.OpenEdgeLexer
pygments.lexers.business.CobolFreeformatLexer
pygments.lexers.business.CobolLexer
pygments.lexers.business.GoodDataCLLexer
pygments.lexers.business.MaqlLexer
pygments.lexers.business.OpenEdgeLexer
pygments.lexers.c_cpp.CLexer
pygments.lexers.c_cpp.CppLexer
pygments.lexers.c_like.ArduinoLexer
pygments.lexers.c_like.CharmciLexer
pygments.lexers.c_like.ClayLexer
pygments.lexers.c_like.CudaLexer
pygments.lexers.c_like.ECLexer
pygments.lexers.c_like.MqlLexer
pygments.lexers.c_like.NesCLexer
pygments.lexers.c_like.OmgIdlLexer
pygments.lexers.c_like.PikeLexer
pygments.lexers.c_like.PromelaLexer
pygments.lexers.c_like.SwigLexer
pygments.lexers.c_like.ValaLexer
pygments.lexers.capnproto.CapnProtoLexer
pygments.lexers.carbon.CarbonLexer
pygments.lexers.cddl.CddlLexer
pygments.lexers.chapel.ChapelLexer
pygments.lexers.clean.CleanLexer
pygments.lexers.c_cpp.CFamilyLexer
pygments.lexers.console.VCTreeStatusLexer
pygments.lexers.console.PyPyLogLexer
pygments.lexers.csound.CsoundLexer
pygments.lexers.csound.CsoundDocumentLexer
pygments.lexers.csound.CsoundDocumentLexer
pygments.lexers.crystal.CrystalLexer
pygments.lexers.dalvik.SmaliLexer
pygments.lexers.css.CssLexer
pygments.lexers.css.SassLexer
pygments.lexers.css.ScssLexer
pygments.lexers.configs.IniLexer
pygments.lexers.configs.RegeditLexer
pygments.lexers.configs.PropertiesLexer
pygments.lexers.configs.KconfigLexer
pygments.lexers.configs.Cfengine3Lexer
pygments.lexers.codeql.CodeQLLexer
pygments.lexers.comal.Comal80Lexer
pygments.lexers.configs.ApacheConfLexer
pygments.lexers.configs.SquidConfLexer
pygments.lexers.configs.NginxConfLexer
pygments.lexers.configs.LighttpdConfLexer
pygments.lexers.configs.AugeasLexer
pygments.lexers.configs.Cfengine3Lexer
pygments.lexers.configs.DesktopLexer
pygments.lexers.configs.DockerLexer
pygments.lexers.configs.TerraformLexer
pygments.lexers.configs.IniLexer
pygments.lexers.configs.KconfigLexer
pygments.lexers.configs.LighttpdConfLexer
pygments.lexers.configs.NestedTextLexer
pygments.lexers.configs.NginxConfLexer
pygments.lexers.configs.PacmanConfLexer
pygments.lexers.configs.PkgConfigLexer
pygments.lexers.configs.PropertiesLexer
pygments.lexers.configs.RegeditLexer
pygments.lexers.configs.SingularityLexer
pygments.lexers.configs.SquidConfLexer
pygments.lexers.configs.SystemdLexer
pygments.lexers.configs.TermcapLexer
pygments.lexers.configs.TerminfoLexer
pygments.lexers.configs.PkgConfigLexer
pygments.lexers.configs.PacmanConfLexer
pygments.lexers.data.YamlLexer
pygments.lexers.configs.TerraformLexer
pygments.lexers.configs.TOMLLexer
pygments.lexers.configs.UnixConfigLexer
pygments.lexers.console.PyPyLogLexer
pygments.lexers.console.VCTreeStatusLexer
pygments.lexers.cplint.CplintLexer
pygments.lexers.crystal.CrystalLexer
pygments.lexers.csound.CsoundDocumentLexer
pygments.lexers.csound.CsoundOrchestraLexer
pygments.lexers.csound.CsoundScoreLexer
pygments.lexers.css.CssLexer
pygments.lexers.css.LessCssLexer
pygments.lexers.css.SassLexer
pygments.lexers.css.ScssLexer
pygments.lexers.d.CrocLexer
pygments.lexers.d.DLexer
pygments.lexers.d.MiniDLexer
pygments.lexers.dalvik.SmaliLexer
pygments.lexers.data.JsonLdLexer
pygments.lexers.data.JsonLexer
pygments.lexers.diff.DiffLexer
pygments.lexers.data.YamlLexer
pygments.lexers.dax.DaxLexer
pygments.lexers.devicetree.DevicetreeLexer
pygments.lexers.diff.DarcsPatchLexer
pygments.lexers.diff.DiffLexer
pygments.lexers.diff.WDiffLexer
pygments.lexers.dotnet.CSharpLexer
pygments.lexers.dotnet.NemerleLexer
pygments.lexers.dns.DnsZoneLexer
pygments.lexers.dotnet.BooLexer
pygments.lexers.dotnet.VbNetLexer
pygments.lexers.dotnet.GenericAspxLexer
pygments.lexers.dotnet.CSharpAspxLexer
pygments.lexers.dotnet.CSharpLexer
pygments.lexers.dotnet.FSharpLexer
pygments.lexers.dotnet.NemerleLexer
pygments.lexers.dotnet.VbNetAspxLexer
pygments.lexers.dotnet.VbNetLexer
pygments.lexers.dotnet.XppLexer
pygments.lexers.dsls.AlloyLexer
pygments.lexers.dsls.CrmshLexer
pygments.lexers.dsls.FlatlineLexer
pygments.lexers.dsls.MscgenLexer
pygments.lexers.dsls.PanLexer
pygments.lexers.dsls.ProtoBufLexer
pygments.lexers.dsls.PuppetLexer
pygments.lexers.dsls.RslLexer
pygments.lexers.dsls.SnowballLexer
pygments.lexers.dsls.ThriftLexer
pygments.lexers.dsls.VGLLexer
pygments.lexers.dsls.ZeekLexer
pygments.lexers.dylan.DylanConsoleLexer
pygments.lexers.dylan.DylanLexer
pygments.lexers.dylan.DylanLidLexer
pygments.lexers.ecl.ECLLexer
pygments.lexers.eiffel.EiffelLexer
pygments.lexers.dsls.ProtoBufLexer
pygments.lexers.dsls.ThriftLexer
pygments.lexers.dsls.BroLexer
pygments.lexers.dsls.PuppetLexer
pygments.lexers.dsls.RslLexer
pygments.lexers.dsls.MscgenLexer
pygments.lexers.dsls.VGLLexer
pygments.lexers.dsls.AlloyLexer
pygments.lexers.dsls.PanLexer
pygments.lexers.dsls.CrmshLexer
pygments.lexers.dsls.FlatlineLexer
pygments.lexers.dsls.SnowballLexer
pygments.lexers.elm.ElmLexer
pygments.lexers.erlang.ErlangLexer
pygments.lexers.elpi.ElpiLexer
pygments.lexers.email.EmailLexer
pygments.lexers.erlang.ElixirConsoleLexer
pygments.lexers.erlang.ElixirLexer
pygments.lexers.ezhil.EzhilLexer
pygments.lexers.esoteric.BrainfuckLexer
pygments.lexers.erlang.ErlangLexer
pygments.lexers.erlang.ErlangShellLexer
pygments.lexers.esoteric.AheuiLexer
pygments.lexers.esoteric.BefungeLexer
pygments.lexers.esoteric.BrainfuckLexer
pygments.lexers.esoteric.CAmkESLexer
pygments.lexers.esoteric.CapDLLexer
pygments.lexers.esoteric.RedcodeLexer
pygments.lexers.esoteric.AheuiLexer
pygments.lexers.ezhil.EzhilLexer
pygments.lexers.factor.FactorLexer
pygments.lexers.fantom.FantomLexer
pygments.lexers.felix.FelixLexer
pygments.lexers.fift.FiftLexer
pygments.lexers.floscript.FloScriptLexer
pygments.lexers.forth.ForthLexer
pygments.lexers.fortran.FortranLexer
pygments.lexers.fortran.FortranFixedLexer
pygments.lexers.go.GoLexer
pygments.lexers.fortran.FortranLexer
pygments.lexers.foxpro.FoxProLexer
pygments.lexers.graph.CypherLexer
pygments.lexers.grammar_notation.BnfLexer
pygments.lexers.freefem.FreeFemLexer
pygments.lexers.func.FuncLexer
pygments.lexers.futhark.FutharkLexer
pygments.lexers.gcodelexer.GcodeLexer
pygments.lexers.gdscript.GDScriptLexer
pygments.lexers.gleam.GleamLexer
pygments.lexers.go.GoLexer
pygments.lexers.grammar_notation.AbnfLexer
pygments.lexers.grammar_notation.BnfLexer
pygments.lexers.grammar_notation.JsgfLexer
pygments.lexers.graphics.GLShaderLexer
pygments.lexers.graphics.PostScriptLexer
pygments.lexers.grammar_notation.PegLexer
pygments.lexers.graph.CypherLexer
pygments.lexers.graphics.AsymptoteLexer
pygments.lexers.graphics.GLShaderLexer
pygments.lexers.graphics.GnuplotLexer
pygments.lexers.graphics.HLSLShaderLexer
pygments.lexers.graphics.PostScriptLexer
pygments.lexers.graphics.PovrayLexer
pygments.lexers.hexdump.HexdumpLexer
pygments.lexers.haskell.HaskellLexer
pygments.lexers.haskell.IdrisLexer
pygments.lexers.graphql.GraphQLLexer
pygments.lexers.graphviz.GraphvizLexer
pygments.lexers.gsql.GSQLLexer
pygments.lexers.hare.HareLexer
pygments.lexers.haskell.AgdaLexer
pygments.lexers.haskell.CryptolLexer
pygments.lexers.haskell.HaskellLexer
pygments.lexers.haskell.HspecLexer
pygments.lexers.haskell.IdrisLexer
pygments.lexers.haskell.KokaLexer
pygments.lexers.haskell.LiterateAgdaLexer
pygments.lexers.haskell.LiterateCryptolLexer
pygments.lexers.haskell.LiterateHaskellLexer
pygments.lexers.haskell.LiterateIdrisLexer
pygments.lexers.haxe.HaxeLexer
pygments.lexers.haxe.HxmlLexer
pygments.lexers.hdl.VerilogLexer
pygments.lexers.hdl.SystemVerilogLexer
pygments.lexers.hdl.VerilogLexer
pygments.lexers.hdl.VhdlLexer
pygments.lexers.idl.IDLLexer
pygments.lexers.inferno.LimboLexer
pygments.lexers.igor.IgorLexer
pygments.lexers.html.HtmlLexer
pygments.lexers.hexdump.HexdumpLexer
pygments.lexers.html.DtdLexer
pygments.lexers.html.XmlLexer
pygments.lexers.html.HamlLexer
pygments.lexers.html.ScamlLexer
pygments.lexers.html.HtmlLexer
pygments.lexers.html.PugLexer
pygments.lexers.html.ScamlLexer
pygments.lexers.html.UrlEncodedLexer
pygments.lexers.html.VueLexer
pygments.lexers.html.XmlLexer
pygments.lexers.html.XsltLexer
pygments.lexers.idl.IDLLexer
pygments.lexers.igor.IgorLexer
pygments.lexers.inferno.LimboLexer
pygments.lexers.installers.DebianControlLexer
pygments.lexers.installers.DebianSourcesLexer
pygments.lexers.installers.NSISLexer
pygments.lexers.installers.RPMSpecLexer
pygments.lexers.installers.SourcesListLexer
pygments.lexers.installers.DebianControlLexer
pygments.lexers.iolang.IoLexer
pygments.lexers.julia.JuliaLexer
pygments.lexers.int_fiction.Inform6Lexer
pygments.lexers.int_fiction.Inform6TemplateLexer
pygments.lexers.int_fiction.Inform7Lexer
pygments.lexers.int_fiction.Tads3Lexer
pygments.lexers.make.BaseMakefileLexer
pygments.lexers.make.CMakeLexer
pygments.lexers.javascript.JavascriptLexer
pygments.lexers.javascript.KalLexer
pygments.lexers.javascript.LiveScriptLexer
pygments.lexers.javascript.DartLexer
pygments.lexers.javascript.TypeScriptLexer
pygments.lexers.javascript.LassoLexer
pygments.lexers.javascript.ObjectiveJLexer
pygments.lexers.iolang.IoLexer
pygments.lexers.j.JLexer
pygments.lexers.javascript.CoffeeScriptLexer
pygments.lexers.javascript.MaskLexer
pygments.lexers.javascript.DartLexer
pygments.lexers.javascript.EarlGreyLexer
pygments.lexers.javascript.JavascriptLexer
pygments.lexers.javascript.JuttleLexer
pygments.lexers.jvm.JavaLexer
pygments.lexers.jvm.ScalaLexer
pygments.lexers.javascript.KalLexer
pygments.lexers.javascript.LassoLexer
pygments.lexers.javascript.LiveScriptLexer
pygments.lexers.javascript.MaskLexer
pygments.lexers.javascript.NodeConsoleLexer
pygments.lexers.javascript.ObjectiveJLexer
pygments.lexers.javascript.TypeScriptLexer
pygments.lexers.jmespath.JMESPathLexer
pygments.lexers.jslt.JSLTLexer
pygments.lexers.json5.Json5Lexer
pygments.lexers.jsonnet.JsonnetLexer
pygments.lexers.jsx.JsxLexer
pygments.lexers.jsx.TsxLexer
pygments.lexers.julia.JuliaConsoleLexer
pygments.lexers.julia.JuliaLexer
pygments.lexers.jvm.AspectJLexer
pygments.lexers.jvm.CeylonLexer
pygments.lexers.jvm.ClojureLexer
pygments.lexers.jvm.ClojureScriptLexer
pygments.lexers.jvm.GoloLexer
pygments.lexers.jvm.GosuLexer
pygments.lexers.jvm.GosuTemplateLexer
pygments.lexers.jvm.GroovyLexer
pygments.lexers.jvm.IokeLexer
pygments.lexers.jvm.ClojureLexer
pygments.lexers.jvm.TeaLangLexer
pygments.lexers.jvm.CeylonLexer
pygments.lexers.jvm.KotlinLexer
pygments.lexers.jvm.XtendLexer
pygments.lexers.jvm.PigLexer
pygments.lexers.jvm.GoloLexer
pygments.lexers.jvm.JasminLexer
pygments.lexers.markup.BBCodeLexer
pygments.lexers.markup.MoinWikiLexer
pygments.lexers.markup.RstLexer
pygments.lexers.markup.TexLexer
pygments.lexers.markup.GroffLexer
pygments.lexers.markup.MozPreprocHashLexer
pygments.lexers.markup.MarkdownLexer
pygments.lexers.ml.SMLLexer
pygments.lexers.ml.OcamlLexer
pygments.lexers.ml.OpaLexer
pygments.lexers.modeling.ModelicaLexer
pygments.lexers.modeling.BugsLexer
pygments.lexers.modeling.JagsLexer
pygments.lexers.modeling.StanLexer
pygments.lexers.matlab.MatlabLexer
pygments.lexers.matlab.OctaveLexer
pygments.lexers.matlab.ScilabLexer
pygments.lexers.monte.MonteLexer
pygments.lexers.lisp.SchemeLexer
pygments.lexers.jvm.JavaLexer
pygments.lexers.jvm.KotlinLexer
pygments.lexers.jvm.PigLexer
pygments.lexers.jvm.SarlLexer
pygments.lexers.jvm.ScalaLexer
pygments.lexers.jvm.XtendLexer
pygments.lexers.kuin.KuinLexer
pygments.lexers.kusto.KustoLexer
pygments.lexers.ldap.LdaprcLexer
pygments.lexers.ldap.LdifLexer
pygments.lexers.lean.Lean3Lexer
pygments.lexers.lean.Lean4Lexer
pygments.lexers.lilypond.LilyPondLexer
pygments.lexers.lisp.CommonLispLexer
pygments.lexers.lisp.HyLexer
pygments.lexers.lisp.RacketLexer
pygments.lexers.lisp.NewLispLexer
pygments.lexers.lisp.CPSALexer
pygments.lexers.lisp.EmacsLispLexer
pygments.lexers.lisp.FennelLexer
pygments.lexers.lisp.HyLexer
pygments.lexers.lisp.JanetLexer
pygments.lexers.lisp.NewLispLexer
pygments.lexers.lisp.RacketLexer
pygments.lexers.lisp.SchemeLexer
pygments.lexers.lisp.ShenLexer
pygments.lexers.lisp.XtlangLexer
pygments.lexers.macaulay2.Macaulay2Lexer
pygments.lexers.make.BaseMakefileLexer
pygments.lexers.make.CMakeLexer
pygments.lexers.make.MakefileLexer
pygments.lexers.maple.MapleLexer
pygments.lexers.markup.BBCodeLexer
pygments.lexers.markup.GroffLexer
pygments.lexers.markup.MarkdownLexer
pygments.lexers.markup.MoinWikiLexer
pygments.lexers.markup.MozPreprocCssLexer
pygments.lexers.markup.MozPreprocHashLexer
pygments.lexers.markup.MozPreprocJavascriptLexer
pygments.lexers.markup.MozPreprocPercentLexer
pygments.lexers.markup.MozPreprocXulLexer
pygments.lexers.markup.OrgLexer
pygments.lexers.markup.RstLexer
pygments.lexers.markup.TexLexer
pygments.lexers.markup.TiddlyWiki5Lexer
pygments.lexers.markup.WikitextLexer
pygments.lexers.matlab.MatlabLexer
pygments.lexers.matlab.MatlabSessionLexer
pygments.lexers.matlab.OctaveLexer
pygments.lexers.matlab.ScilabLexer
pygments.lexers.maxima.MaximaLexer
pygments.lexers.meson.MesonLexer
pygments.lexers.mime.MIMELexer
pygments.lexers.minecraft.MCFunctionLexer
pygments.lexers.minecraft.MCSchemaLexer
pygments.lexers.minecraft.SNBTLexer
pygments.lexers.mips.MIPSLexer
pygments.lexers.ml.FStarLexer
pygments.lexers.ml.OcamlLexer
pygments.lexers.ml.OpaLexer
pygments.lexers.ml.ReasonLexer
pygments.lexers.ml.SMLLexer
pygments.lexers.modeling.BugsLexer
pygments.lexers.modeling.JagsLexer
pygments.lexers.modeling.ModelicaLexer
pygments.lexers.modeling.StanLexer
pygments.lexers.modula2.Modula2Lexer
pygments.lexers.mojo.MojoLexer
pygments.lexers.monte.MonteLexer
pygments.lexers.mosel.MoselLexer
pygments.lexers.ncl.NCLLexer
pygments.lexers.nim.NimLexer
pygments.lexers.nimrod.NimrodLexer
pygments.lexers.nit.NitLexer
pygments.lexers.nix.NixLexer
pygments.lexers.numbair.NumbaIRLexer
pygments.lexers.oberon.ComponentPascalLexer
pygments.lexers.ooc.OocLexer
pygments.lexers.objective.LogosLexer
pygments.lexers.objective.ObjectiveCLexer
pygments.lexers.objective.ObjectiveCppLexer
pygments.lexers.objective.SwiftLexer
pygments.lexers.ooc.OocLexer
pygments.lexers.openscad.OpenScadLexer
pygments.lexers.parasail.ParaSailLexer
pygments.lexers.pawn.SourcePawnLexer
pygments.lexers.pawn.PawnLexer
pygments.lexers.pascal.AdaLexer
pygments.lexers.parsers.RagelLexer
pygments.lexers.parsers.RagelEmbeddedLexer
pygments.lexers.parsers.AntlrActionScriptLexer
pygments.lexers.parsers.AntlrCppLexer
pygments.lexers.parsers.AntlrCSharpLexer
pygments.lexers.parsers.AntlrJavaLexer
pygments.lexers.parsers.AntlrLexer
pygments.lexers.parsers.TreetopBaseLexer
pygments.lexers.parsers.AntlrObjectiveCLexer
pygments.lexers.parsers.AntlrPerlLexer
pygments.lexers.parsers.AntlrPythonLexer
pygments.lexers.parsers.AntlrRubyLexer
pygments.lexers.parsers.EbnfLexer
pygments.lexers.php.ZephirLexer
pygments.lexers.php.PhpLexer
pygments.lexers.perl.PerlLexer
pygments.lexers.parsers.RagelCLexer
pygments.lexers.parsers.RagelCppLexer
pygments.lexers.parsers.RagelDLexer
pygments.lexers.parsers.RagelEmbeddedLexer
pygments.lexers.parsers.RagelJavaLexer
pygments.lexers.parsers.RagelLexer
pygments.lexers.parsers.RagelObjectiveCLexer
pygments.lexers.parsers.RagelRubyLexer
pygments.lexers.parsers.TreetopLexer
pygments.lexers.pascal.DelphiLexer
pygments.lexers.pascal.PortugolLexer
pygments.lexers.pawn.PawnLexer
pygments.lexers.pawn.SourcePawnLexer
pygments.lexers.pddl.PddlLexer
pygments.lexers.perl.Perl6Lexer
pygments.lexers.perl.PerlLexer
pygments.lexers.phix.PhixLexer
pygments.lexers.php.PhpLexer
pygments.lexers.php.PsyshConsoleLexer
pygments.lexers.php.ZephirLexer
pygments.lexers.pointless.PointlessLexer
pygments.lexers.pony.PonyLexer
pygments.lexers.praat.PraatLexer
pygments.lexers.prolog.PrologLexer
pygments.lexers.procfile.ProcfileLexer
pygments.lexers.prolog.LogtalkLexer
pygments.lexers.qvt.QVToLexer
pygments.lexers.rdf.SparqlLexer
pygments.lexers.rdf.TurtleLexer
pygments.lexers.python.PythonLexer
pygments.lexers.python.Python3Lexer
pygments.lexers.python.PythonTracebackLexer
pygments.lexers.python.Python3TracebackLexer
pygments.lexers.prolog.PrologLexer
pygments.lexers.promql.PromQLLexer
pygments.lexers.prql.PrqlLexer
pygments.lexers.ptx.PtxLexer
pygments.lexers.python.CythonLexer
pygments.lexers.python.DgLexer
pygments.lexers.python.NumPyLexer
pygments.lexers.python.Python2Lexer
pygments.lexers.python.Python2TracebackLexer
pygments.lexers.python.PythonConsoleLexer
pygments.lexers.python.PythonLexer
pygments.lexers.python.PythonTracebackLexer
pygments.lexers.q.KLexer
pygments.lexers.q.QLexer
pygments.lexers.qlik.QlikLexer
pygments.lexers.qvt.QVToLexer
pygments.lexers.r.RConsoleLexer
pygments.lexers.r.RdLexer
pygments.lexers.r.SLexer
pygments.lexers.rdf.ShExCLexer
pygments.lexers.rdf.SparqlLexer
pygments.lexers.rdf.TurtleLexer
pygments.lexers.rebol.RebolLexer
pygments.lexers.rebol.RedLexer
pygments.lexers.rego.RegoLexer
pygments.lexers.resource.ResourceLexer
pygments.lexers.ride.RideLexer
pygments.lexers.rita.RitaLexer
pygments.lexers.rnc.RNCCompactLexer
pygments.lexers.roboconf.RoboconfGraphLexer
pygments.lexers.roboconf.RoboconfInstancesLexer
pygments.lexers.rust.RustLexer
pygments.lexers.ruby.RubyLexer
pygments.lexers.robotframework.RobotFrameworkLexer
pygments.lexers.ruby.FancyLexer
pygments.lexers.ruby.RubyConsoleLexer
pygments.lexers.ruby.RubyLexer
pygments.lexers.rust.RustLexer
pygments.lexers.sas.SASLexer
pygments.lexers.smalltalk.SmalltalkLexer
pygments.lexers.smalltalk.NewspeakLexer
pygments.lexers.smv.NuSMVLexer
pygments.lexers.shell.BashLexer
pygments.lexers.shell.BatchLexer
pygments.lexers.shell.TcshLexer
pygments.lexers.shell.PowerShellLexer
pygments.lexers.shell.FishShellLexer
pygments.lexers.snobol.SnobolLexer
pygments.lexers.scripting.LuaLexer
pygments.lexers.scripting.ChaiscriptLexer
pygments.lexers.scripting.LSLLexer
pygments.lexers.savi.SaviLexer
pygments.lexers.scdoc.ScdocLexer
pygments.lexers.scripting.AppleScriptLexer
pygments.lexers.scripting.RexxLexer
pygments.lexers.scripting.MOOCodeLexer
pygments.lexers.scripting.HybrisLexer
pygments.lexers.scripting.ChaiscriptLexer
pygments.lexers.scripting.EasytrieveLexer
pygments.lexers.scripting.HybrisLexer
pygments.lexers.scripting.JclLexer
pygments.lexers.supercollider.SuperColliderLexer
pygments.lexers.stata.StataLexer
pygments.lexers.tcl.TclLexer
pygments.lexers.sql.PostgresLexer
pygments.lexers.scripting.LSLLexer
pygments.lexers.scripting.LuaLexer
pygments.lexers.scripting.LuauLexer
pygments.lexers.scripting.MiniScriptLexer
pygments.lexers.scripting.MOOCodeLexer
pygments.lexers.scripting.MoonScriptLexer
pygments.lexers.scripting.RexxLexer
pygments.lexers.sgf.SmartGameFormatLexer
pygments.lexers.shell.BashLexer
pygments.lexers.shell.BashSessionLexer
pygments.lexers.shell.BatchLexer
pygments.lexers.shell.ExeclineLexer
pygments.lexers.shell.FishShellLexer
pygments.lexers.shell.MSDOSSessionLexer
pygments.lexers.shell.PowerShellLexer
pygments.lexers.shell.PowerShellSessionLexer
pygments.lexers.shell.SlurmBashLexer
pygments.lexers.shell.TcshLexer
pygments.lexers.shell.TcshSessionLexer
pygments.lexers.sieve.SieveLexer
pygments.lexers.slash.SlashLexer
pygments.lexers.smalltalk.NewspeakLexer
pygments.lexers.smalltalk.SmalltalkLexer
pygments.lexers.smithy.SmithyLexer
pygments.lexers.smv.NuSMVLexer
pygments.lexers.snobol.SnobolLexer
pygments.lexers.solidity.SolidityLexer
pygments.lexers.soong.SoongLexer
pygments.lexers.sophia.SophiaLexer
pygments.lexers.special.OutputLexer
pygments.lexers.special.TextLexer
pygments.lexers.spice.SpiceLexer
pygments.lexers.sql.GoogleSqlLexer
pygments.lexers.sql.MySqlLexer
pygments.lexers.sql.PlPgsqlLexer
pygments.lexers.sql.PsqlRegexLexer
pygments.lexers.sql.PostgresConsoleLexer
pygments.lexers.sql.PostgresExplainLexer
pygments.lexers.sql.PostgresLexer
pygments.lexers.sql.RqlLexer
pygments.lexers.sql.SqliteConsoleLexer
pygments.lexers.sql.SqlLexer
pygments.lexers.sql.TransactSqlLexer
pygments.lexers.sql.MySqlLexer
pygments.lexers.sql.RqlLexer
pygments.lexers.srcinfo.SrcinfoLexer
pygments.lexers.stata.StataLexer
pygments.lexers.supercollider.SuperColliderLexer
pygments.lexers.tablegen.TableGenLexer
pygments.lexers.tact.TactLexer
pygments.lexers.tal.TalLexer
pygments.lexers.tcl.TclLexer
pygments.lexers.teal.TealLexer
pygments.lexers.templates.Angular2HtmlLexer
pygments.lexers.templates.Angular2Lexer
pygments.lexers.templates.CheetahHtmlLexer
pygments.lexers.templates.CheetahJavascriptLexer
pygments.lexers.templates.CheetahLexer
pygments.lexers.templates.CheetahXmlLexer
pygments.lexers.templates.ColdfusionCFCLexer
pygments.lexers.templates.ColdfusionHtmlLexer
pygments.lexers.templates.ColdfusionLexer
pygments.lexers.templates.CssDjangoLexer
pygments.lexers.templates.CssErbLexer
pygments.lexers.templates.CssGenshiLexer
pygments.lexers.templates.CssPhpLexer
pygments.lexers.templates.CssSmartyLexer
pygments.lexers.templates.DjangoLexer
pygments.lexers.templates.ErbLexer
pygments.lexers.templates.EvoqueHtmlLexer
pygments.lexers.templates.EvoqueLexer
pygments.lexers.templates.EvoqueXmlLexer
pygments.lexers.templates.GenshiLexer
pygments.lexers.templates.GenshiTextLexer
pygments.lexers.templates.HandlebarsHtmlLexer
pygments.lexers.templates.HandlebarsLexer
pygments.lexers.templates.HtmlDjangoLexer
pygments.lexers.templates.HtmlGenshiLexer
pygments.lexers.templates.HtmlPhpLexer
pygments.lexers.templates.HtmlSmartyLexer
pygments.lexers.templates.JavascriptDjangoLexer
pygments.lexers.templates.JavascriptErbLexer
pygments.lexers.templates.JavascriptGenshiLexer
pygments.lexers.templates.JavascriptPhpLexer
pygments.lexers.templates.JavascriptSmartyLexer
pygments.lexers.templates.JspLexer
pygments.lexers.templates.LassoCssLexer
pygments.lexers.templates.LassoHtmlLexer
pygments.lexers.templates.LassoJavascriptLexer
pygments.lexers.templates.LassoXmlLexer
pygments.lexers.templates.LiquidLexer
pygments.lexers.templates.MakoCssLexer
pygments.lexers.templates.MakoHtmlLexer
pygments.lexers.templates.MakoJavascriptLexer
pygments.lexers.templates.MakoLexer
pygments.lexers.templates.MakoXmlLexer
pygments.lexers.templates.MasonLexer
pygments.lexers.templates.MyghtyCssLexer
pygments.lexers.templates.MyghtyHtmlLexer
pygments.lexers.templates.MyghtyJavascriptLexer
pygments.lexers.templates.MyghtyLexer
pygments.lexers.templates.MyghtyXmlLexer
pygments.lexers.templates.RhtmlLexer
pygments.lexers.templates.SmartyLexer
pygments.lexers.templates.SqlJinjaLexer
pygments.lexers.templates.SspLexer
pygments.lexers.templates.TeaTemplateLexer
pygments.lexers.templates.TwigHtmlLexer
pygments.lexers.templates.TwigLexer
pygments.lexers.templates.VelocityHtmlLexer
pygments.lexers.templates.VelocityLexer
pygments.lexers.templates.VelocityXmlLexer
pygments.lexers.templates.XmlDjangoLexer
pygments.lexers.templates.XmlErbLexer
pygments.lexers.templates.XmlPhpLexer
pygments.lexers.templates.XmlSmartyLexer
pygments.lexers.templates.YamlJinjaLexer
pygments.lexers.teraterm.TeraTermLexer
pygments.lexers.testing.GherkinLexer
pygments.lexers.testing.TAPLexer
pygments.lexers.textedit.AwkLexer
pygments.lexers.textedit.SedLexer
pygments.lexers.textedit.VimLexer
pygments.lexers.textfmts.IrcLogsLexer
pygments.lexers.textfmts.GettextLexer
pygments.lexers.textfmts.HttpLexer
pygments.lexers.textfmts.IrcLogsLexer
pygments.lexers.textfmts.KernelLogLexer
pygments.lexers.textfmts.NotmuchLexer
pygments.lexers.textfmts.TodotxtLexer
pygments.lexers.trafficscript.RtsLexer
pygments.lexers.theorem.CoqLexer
pygments.lexers.theorem.IsabelleLexer
pygments.lexers.theorem.LeanLexer
pygments.lexers.templates.SmartyLexer
pygments.lexers.templates.VelocityLexer
pygments.lexers.templates.DjangoLexer
pygments.lexers.templates.MyghtyLexer
pygments.lexers.templates.MasonLexer
pygments.lexers.templates.MakoLexer
pygments.lexers.templates.CheetahLexer
pygments.lexers.templates.GenshiTextLexer
pygments.lexers.templates.GenshiMarkupLexer
pygments.lexers.templates.JspRootLexer
pygments.lexers.templates.EvoqueLexer
pygments.lexers.templates.ColdfusionLexer
pygments.lexers.templates.ColdfusionMarkupLexer
pygments.lexers.templates.TeaTemplateRootLexer
pygments.lexers.templates.HandlebarsLexer
pygments.lexers.templates.LiquidLexer
pygments.lexers.templates.TwigLexer
pygments.lexers.templates.Angular2Lexer
pygments.lexers.urbi.UrbiscriptLexer
pygments.lexers.thingsdb.ThingsDBLexer
pygments.lexers.tlb.TlbLexer
pygments.lexers.tls.TlsLexer
pygments.lexers.tnt.TNTLexer
pygments.lexers.trafficscript.RtsLexer
pygments.lexers.typoscript.TypoScriptCssDataLexer
pygments.lexers.typoscript.TypoScriptHtmlDataLexer
pygments.lexers.typoscript.TypoScriptLexer
pygments.lexers.typst.TypstLexer
pygments.lexers.ul4.CSSUL4Lexer
pygments.lexers.ul4.HTMLUL4Lexer
pygments.lexers.ul4.JavascriptUL4Lexer
pygments.lexers.ul4.PythonUL4Lexer
pygments.lexers.ul4.UL4Lexer
pygments.lexers.ul4.XMLUL4Lexer
pygments.lexers.unicon.IconLexer
pygments.lexers.unicon.UcodeLexer
pygments.lexers.unicon.UniconLexer
pygments.lexers.urbi.UrbiscriptLexer
pygments.lexers.usd.UsdLexer
pygments.lexers.varnish.VCLLexer
pygments.lexers.varnish.VCLSnippetLexer
pygments.lexers.verification.BoogieLexer
pygments.lexers.verification.SilverLexer
pygments.lexers.x10.X10Lexer
pygments.lexers.whiley.WhileyLexer
pygments.lexers.xorg.XorgLexer
pygments.lexers.webmisc.DuelLexer
pygments.lexers.webmisc.XQueryLexer
pygments.lexers.webmisc.QmlLexer
pygments.lexers.verifpal.VerifpalLexer
pygments.lexers.vip.VisualPrologGrammarLexer
pygments.lexers.vip.VisualPrologLexer
pygments.lexers.vyper.VyperLexer
pygments.lexers.webassembly.WatLexer
pygments.lexers.webidl.WebIDLLexer
pygments.lexers.webmisc.CirruLexer
pygments.lexers.webmisc.DuelLexer
pygments.lexers.webmisc.QmlLexer
pygments.lexers.webmisc.SlimLexer
pygments.lexers.webmisc.XQueryLexer
pygments.lexers.wgsl.WgslLexer
pygments.lexers.whiley.WhileyLexer
pygments.lexers.wowtoc.WoWTocLexer
pygments.lexers.wren.WrenLexer
pygments.lexers.x10.X10Lexer
pygments.lexers.xorg.XorgLexer
pygments.lexers.yang.YangLexer
pygments.lexers.yara.YaraLexer
pygments.lexers.zig.ZigLexer
+46 -5
View File
@@ -1,6 +1,7 @@
package chroma
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
@@ -135,11 +136,20 @@ func NewLexer(config *Config, rulesFunc func() Rules) (*RegexLexer, error) {
}
// Trace enables debug tracing.
//
// Deprecated: Use SetTracing instead.
func (r *RegexLexer) Trace(trace bool) *RegexLexer {
r.trace = trace
return r
}
// SetTracing enables debug tracing.
//
// This complies with the [TracingLexer] interface.
func (r *RegexLexer) SetTracing(trace bool) {
r.trace = trace
}
// A CompiledRule is a Rule with a pre-compiled regex.
//
// Note that regular expressions are lazily compiled on first use of the lexer.
@@ -185,6 +195,7 @@ func (l *LexerState) Get(key interface{}) interface{} {
// Iterator returns the next Token from the lexer.
func (l *LexerState) Iterator() Token { // nolint: gocognit
trace := json.NewEncoder(os.Stderr)
end := len(l.Text)
if l.newlineAdded {
end--
@@ -205,14 +216,33 @@ func (l *LexerState) Iterator() Token { // nolint: gocognit
}
l.State = l.Stack[len(l.Stack)-1]
if l.Lexer.trace {
fmt.Fprintf(os.Stderr, "%s: pos=%d, text=%q\n", l.State, l.Pos, string(l.Text[l.Pos:]))
}
selectedRule, ok := l.Rules[l.State]
if !ok {
panic("unknown state " + l.State)
}
var start time.Time
if l.Lexer.trace {
start = time.Now()
}
ruleIndex, rule, groups, namedGroups := matchRules(l.Text, l.Pos, selectedRule)
if l.Lexer.trace {
var length int
if groups != nil {
length = len(groups[0])
} else {
length = -1
}
_ = trace.Encode(Trace{ //nolint
Lexer: l.Lexer.config.Name,
State: l.State,
Rule: ruleIndex,
Pattern: rule.Pattern,
Pos: l.Pos,
Length: length,
Elapsed: float64(time.Since(start)) / float64(time.Millisecond),
})
// fmt.Fprintf(os.Stderr, "%s: pos=%d, text=%q, elapsed=%s\n", l.State, l.Pos, string(l.Text[l.Pos:]), time.Since(start))
}
// No match.
if groups == nil {
// From Pygments :\
@@ -349,7 +379,7 @@ func (r *RegexLexer) maybeCompile() (err error) {
restart:
seen := map[LexerMutator]bool{}
for state := range r.rules {
for i := 0; i < len(r.rules[state]); i++ {
for i := range len(r.rules[state]) {
rule := r.rules[state][i]
if compile, ok := rule.Mutator.(LexerMutator); ok {
if seen[compile] {
@@ -366,6 +396,17 @@ restart:
}
}
}
// Validate emitters
for state := range r.rules {
for i := range len(r.rules[state]) {
rule := r.rules[state][i]
if validate, ok := rule.Type.(ValidatingEmitter); ok {
if err := validate.ValidateEmitter(rule); err != nil {
return fmt.Errorf("%s: %s: %s: %w", r.config.Name, state, rule.Pattern, err)
}
}
}
}
r.compiled = true
return nil
}
@@ -474,7 +515,7 @@ func matchRules(text []rune, pos int, rules []*CompiledRule) (int, *CompiledRule
func ensureLF(text string) string {
buf := make([]byte, len(text))
var j int
for i := 0; i < len(text); i++ {
for i := range len(text) {
c := text[i]
if c == '\r' {
if i < len(text)-1 && text[i+1] == '\n' {
+18
View File
@@ -48,6 +48,24 @@ func (l *LexerRegistry) Names(withAliases bool) []string {
return out
}
// Aliases of all the lexers, and skip those lexers who do not have any aliases,
// or show their name instead
func (l *LexerRegistry) Aliases(skipWithoutAliases bool) []string {
out := []string{}
for _, lexer := range l.Lexers {
config := lexer.Config()
if len(config.Aliases) == 0 {
if skipWithoutAliases {
continue
}
out = append(out, config.Name)
}
out = append(out, config.Aliases...)
}
sort.Strings(out)
return out
}
// Get a Lexer by name, alias or file extension.
func (l *LexerRegistry) Get(name string) Lexer {
if lexer := l.byName[name]; lexer != nil {
+13 -7
View File
@@ -1,18 +1,24 @@
{
$schema: "https://docs.renovatebot.com/renovate-schema.json",
extends: [
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:recommended",
":semanticCommits",
":semanticCommitTypeAll(chore)",
":semanticCommitScope(deps)",
"group:allNonMajor",
"schedule:earlyMondays", // Run once a week.
'helpers:pinGitHubActionDigests',
],
packageRules: [
"packageRules": [
{
matchPackageNames: ["golangci-lint"],
matchManagers: ["hermit"],
enabled: false,
"matchPackageNames": ["golangci-lint"],
"matchManagers": ["hermit"],
"enabled": false
},
],
{
"matchPackageNames": ["github.com/gorilla/csrf"],
"matchManagers": ["gomod"],
"enabled": false
}
]
}
@@ -65,12 +65,12 @@
<entry type="CommentSingle" style="italic #737994"/>
<entry type="CommentMultiline" style="italic #737994"/>
<entry type="CommentSpecial" style="italic #737994"/>
<entry type="CommentHashbang" style="italic #737994"/>
<entry type="CommentHashbang" style="italic #626880"/>
<entry type="CommentPreproc" style="italic #737994"/>
<entry type="CommentPreprocFile" style="bold #737994"/>
<entry type="Generic" style="#c6d0f5"/>
<entry type="GenericInserted" style="bg:#414559 #a6d189"/>
<entry type="GenericDeleted" style="#e78284 bg:#414559"/>
<entry type="GenericDeleted" style="bg:#414559 #e78284"/>
<entry type="GenericEmph" style="italic #c6d0f5"/>
<entry type="GenericStrong" style="bold #c6d0f5"/>
<entry type="GenericUnderline" style="underline #c6d0f5"/>
@@ -80,4 +80,4 @@
<entry type="GenericPrompt" style="#c6d0f5"/>
<entry type="GenericError" style="#e78284"/>
<entry type="GenericTraceback" style="#e78284"/>
</style>
</style>
@@ -65,12 +65,12 @@
<entry type="CommentSingle" style="italic #9ca0b0"/>
<entry type="CommentMultiline" style="italic #9ca0b0"/>
<entry type="CommentSpecial" style="italic #9ca0b0"/>
<entry type="CommentHashbang" style="italic #9ca0b0"/>
<entry type="CommentHashbang" style="italic #acb0be"/>
<entry type="CommentPreproc" style="italic #9ca0b0"/>
<entry type="CommentPreprocFile" style="bold #9ca0b0"/>
<entry type="Generic" style="#4c4f69"/>
<entry type="GenericInserted" style="bg:#ccd0da #40a02b"/>
<entry type="GenericDeleted" style="#d20f39 bg:#ccd0da"/>
<entry type="GenericDeleted" style="bg:#ccd0da #d20f39"/>
<entry type="GenericEmph" style="italic #4c4f69"/>
<entry type="GenericStrong" style="bold #4c4f69"/>
<entry type="GenericUnderline" style="underline #4c4f69"/>
@@ -80,4 +80,4 @@
<entry type="GenericPrompt" style="#4c4f69"/>
<entry type="GenericError" style="#d20f39"/>
<entry type="GenericTraceback" style="#d20f39"/>
</style>
</style>
@@ -65,12 +65,12 @@
<entry type="CommentSingle" style="italic #6e738d"/>
<entry type="CommentMultiline" style="italic #6e738d"/>
<entry type="CommentSpecial" style="italic #6e738d"/>
<entry type="CommentHashbang" style="italic #6e738d"/>
<entry type="CommentHashbang" style="italic #5b6078"/>
<entry type="CommentPreproc" style="italic #6e738d"/>
<entry type="CommentPreprocFile" style="bold #6e738d"/>
<entry type="Generic" style="#cad3f5"/>
<entry type="GenericInserted" style="bg:#363a4f #a6da95"/>
<entry type="GenericDeleted" style="#ed8796 bg:#363a4f"/>
<entry type="GenericDeleted" style="bg:#363a4f #ed8796"/>
<entry type="GenericEmph" style="italic #cad3f5"/>
<entry type="GenericStrong" style="bold #cad3f5"/>
<entry type="GenericUnderline" style="underline #cad3f5"/>
@@ -80,4 +80,4 @@
<entry type="GenericPrompt" style="#cad3f5"/>
<entry type="GenericError" style="#ed8796"/>
<entry type="GenericTraceback" style="#ed8796"/>
</style>
</style>
@@ -65,12 +65,12 @@
<entry type="CommentSingle" style="italic #6c7086"/>
<entry type="CommentMultiline" style="italic #6c7086"/>
<entry type="CommentSpecial" style="italic #6c7086"/>
<entry type="CommentHashbang" style="italic #6c7086"/>
<entry type="CommentHashbang" style="italic #585b70"/>
<entry type="CommentPreproc" style="italic #6c7086"/>
<entry type="CommentPreprocFile" style="bold #6c7086"/>
<entry type="Generic" style="#cdd6f4"/>
<entry type="GenericInserted" style="bg:#313244 #a6e3a1"/>
<entry type="GenericDeleted" style="#f38ba8 bg:#313244"/>
<entry type="GenericDeleted" style="bg:#313244 #f38ba8"/>
<entry type="GenericEmph" style="italic #cdd6f4"/>
<entry type="GenericStrong" style="bold #cdd6f4"/>
<entry type="GenericUnderline" style="underline #cdd6f4"/>
@@ -80,4 +80,4 @@
<entry type="GenericPrompt" style="#cdd6f4"/>
<entry type="GenericError" style="#f38ba8"/>
<entry type="GenericTraceback" style="#f38ba8"/>
</style>
</style>
+30
View File
@@ -0,0 +1,30 @@
<style name="RPGLE">
<entry type="Error" style="#960050 bg:#1e0010"/>
<entry type="Background" style="bg:#fafafa"/>
<entry type="Keyword" style="#00a8c8"/>
<entry type="KeywordNamespace" style="#f92672"/>
<entry type="KeywordReserved" style="#0000ff"/>
<entry type="KeywordType" style="#800000"/>
<entry type="Name" style="#111111"/>
<entry type="NameAttribute" style="#75af00"/>
<entry type="NameClass" style="#75af00"/>
<entry type="NameConstant" style="#00a8c8"/>
<entry type="NameDecorator" style="#75af00"/>
<entry type="NameException" style="#75af00"/>
<entry type="NameFunction" style="#75af00"/>
<entry type="NameOther" style="#75af00"/>
<entry type="NameTag" style="#f92672"/>
<entry type="Literal" style="#ae81ff"/>
<entry type="LiteralDate" style="#d88200"/>
<entry type="LiteralString" style="#d88200"/>
<entry type="LiteralStringEscape" style="#8045ff"/>
<entry type="LiteralNumber" style="#ae81ff"/>
<entry type="Operator" style="#f92672"/>
<entry type="Punctuation" style="#ff0000"/>
<entry type="Comment" style="#75715e"/>
<entry type="CommentPreproc" style="#2e7d32"/>
<entry type="CommentSpecial" style="#ffbf00"/>
<entry type="GenericEmph" style="italic"/>
<entry type="GenericStrong" style="bold"/>
<entry type="Text" style="#272822"/>
</style>
+6
View File
@@ -10,4 +10,10 @@
<entry type="LiteralNumber" style="#ff6600"/>
<entry type="Comment" style="#00ff00"/>
<entry type="CommentPreproc" style="#e5e5e5"/>
<entry type="GenericDeleted" style="#f00"/>
<entry type="GenericEmph" style="italic"/>
<entry type="GenericHeading" style="bold #ff0"/>
<entry type="GenericInserted" style="#0f0"/>
<entry type="GenericStrong" style="bold"/>
<entry type="GenericSubheading" style="bold #87ceeb"/>
</style>
+117 -117
View File
@@ -7,8 +7,8 @@ import (
"strings"
)
const _TokenTypeName = "IgnoreNoneOtherErrorCodeLineLineLinkLineTableTDLineTableLineHighlightLineNumbersTableLineNumbersLinePreWrapperBackgroundEOFTypeKeywordKeywordConstantKeywordDeclarationKeywordNamespaceKeywordPseudoKeywordReservedKeywordTypeNameNameAttributeNameBuiltinNameBuiltinPseudoNameClassNameConstantNameDecoratorNameEntityNameExceptionNameFunctionNameFunctionMagicNameKeywordNameLabelNameNamespaceNameOperatorNameOtherNamePseudoNamePropertyNameTagNameVariableNameVariableAnonymousNameVariableClassNameVariableGlobalNameVariableInstanceNameVariableMagicLiteralLiteralDateLiteralOtherLiteralStringLiteralStringAffixLiteralStringAtomLiteralStringBacktickLiteralStringBooleanLiteralStringCharLiteralStringDelimiterLiteralStringDocLiteralStringDoubleLiteralStringEscapeLiteralStringHeredocLiteralStringInterpolLiteralStringNameLiteralStringOtherLiteralStringRegexLiteralStringSingleLiteralStringSymbolLiteralNumberLiteralNumberBinLiteralNumberFloatLiteralNumberHexLiteralNumberIntegerLiteralNumberIntegerLongLiteralNumberOctLiteralNumberByteOperatorOperatorWordPunctuationCommentCommentHashbangCommentMultilineCommentSingleCommentSpecialCommentPreprocCommentPreprocFileGenericGenericDeletedGenericEmphGenericErrorGenericHeadingGenericInsertedGenericOutputGenericPromptGenericStrongGenericSubheadingGenericTracebackGenericUnderlineTextTextWhitespaceTextSymbolTextPunctuation"
const _TokenTypeLowerName = "ignorenoneothererrorcodelinelinelinklinetabletdlinetablelinehighlightlinenumberstablelinenumberslineprewrapperbackgroundeoftypekeywordkeywordconstantkeyworddeclarationkeywordnamespacekeywordpseudokeywordreservedkeywordtypenamenameattributenamebuiltinnamebuiltinpseudonameclassnameconstantnamedecoratornameentitynameexceptionnamefunctionnamefunctionmagicnamekeywordnamelabelnamenamespacenameoperatornameothernamepseudonamepropertynametagnamevariablenamevariableanonymousnamevariableclassnamevariableglobalnamevariableinstancenamevariablemagicliteralliteraldateliteralotherliteralstringliteralstringaffixliteralstringatomliteralstringbacktickliteralstringbooleanliteralstringcharliteralstringdelimiterliteralstringdocliteralstringdoubleliteralstringescapeliteralstringheredocliteralstringinterpolliteralstringnameliteralstringotherliteralstringregexliteralstringsingleliteralstringsymbolliteralnumberliteralnumberbinliteralnumberfloatliteralnumberhexliteralnumberintegerliteralnumberintegerlongliteralnumberoctliteralnumberbyteoperatoroperatorwordpunctuationcommentcommenthashbangcommentmultilinecommentsinglecommentspecialcommentpreproccommentpreprocfilegenericgenericdeletedgenericemphgenericerrorgenericheadinggenericinsertedgenericoutputgenericpromptgenericstronggenericsubheadinggenerictracebackgenericunderlinetexttextwhitespacetextsymboltextpunctuation"
const _TokenTypeName = "IgnoreNoneOtherErrorCodeLineLineLinkLineTableTDLineTableLineHighlightLineNumbersTableLineNumbersLinePreWrapperBackgroundEOFTypeKeywordKeywordConstantKeywordDeclarationKeywordNamespaceKeywordPseudoKeywordReservedKeywordTypeNameNameAttributeNameClassNameConstantNameDecoratorNameEntityNameExceptionNameKeywordNameLabelNameNamespaceNameOperatorNameOtherNamePseudoNamePropertyNameTagNameBuiltinNameBuiltinPseudoNameVariableNameVariableAnonymousNameVariableClassNameVariableGlobalNameVariableInstanceNameVariableMagicNameFunctionNameFunctionMagicLiteralLiteralDateLiteralOtherLiteralStringLiteralStringAffixLiteralStringAtomLiteralStringBacktickLiteralStringBooleanLiteralStringCharLiteralStringDelimiterLiteralStringDocLiteralStringDoubleLiteralStringEscapeLiteralStringHeredocLiteralStringInterpolLiteralStringNameLiteralStringOtherLiteralStringRegexLiteralStringSingleLiteralStringSymbolLiteralNumberLiteralNumberBinLiteralNumberFloatLiteralNumberHexLiteralNumberIntegerLiteralNumberIntegerLongLiteralNumberOctLiteralNumberByteOperatorOperatorWordPunctuationCommentCommentHashbangCommentMultilineCommentSingleCommentSpecialCommentPreprocCommentPreprocFileGenericGenericDeletedGenericEmphGenericErrorGenericHeadingGenericInsertedGenericOutputGenericPromptGenericStrongGenericSubheadingGenericTracebackGenericUnderlineTextTextWhitespaceTextSymbolTextPunctuation"
const _TokenTypeLowerName = "ignorenoneothererrorcodelinelinelinklinetabletdlinetablelinehighlightlinenumberstablelinenumberslineprewrapperbackgroundeoftypekeywordkeywordconstantkeyworddeclarationkeywordnamespacekeywordpseudokeywordreservedkeywordtypenamenameattributenameclassnameconstantnamedecoratornameentitynameexceptionnamekeywordnamelabelnamenamespacenameoperatornameothernamepseudonamepropertynametagnamebuiltinnamebuiltinpseudonamevariablenamevariableanonymousnamevariableclassnamevariableglobalnamevariableinstancenamevariablemagicnamefunctionnamefunctionmagicliteralliteraldateliteralotherliteralstringliteralstringaffixliteralstringatomliteralstringbacktickliteralstringbooleanliteralstringcharliteralstringdelimiterliteralstringdocliteralstringdoubleliteralstringescapeliteralstringheredocliteralstringinterpolliteralstringnameliteralstringotherliteralstringregexliteralstringsingleliteralstringsymbolliteralnumberliteralnumberbinliteralnumberfloatliteralnumberhexliteralnumberintegerliteralnumberintegerlongliteralnumberoctliteralnumberbyteoperatoroperatorwordpunctuationcommentcommenthashbangcommentmultilinecommentsinglecommentspecialcommentpreproccommentpreprocfilegenericgenericdeletedgenericemphgenericerrorgenericheadinggenericinsertedgenericoutputgenericpromptgenericstronggenericsubheadinggenerictracebackgenericunderlinetexttextwhitespacetextsymboltextpunctuation"
var _TokenTypeMap = map[TokenType]string{
-14: _TokenTypeName[0:6],
@@ -35,29 +35,29 @@ var _TokenTypeMap = map[TokenType]string{
1006: _TokenTypeName[211:222],
2000: _TokenTypeName[222:226],
2001: _TokenTypeName[226:239],
2002: _TokenTypeName[239:250],
2003: _TokenTypeName[250:267],
2004: _TokenTypeName[267:276],
2005: _TokenTypeName[276:288],
2006: _TokenTypeName[288:301],
2007: _TokenTypeName[301:311],
2008: _TokenTypeName[311:324],
2009: _TokenTypeName[324:336],
2010: _TokenTypeName[336:353],
2011: _TokenTypeName[353:364],
2012: _TokenTypeName[364:373],
2013: _TokenTypeName[373:386],
2014: _TokenTypeName[386:398],
2015: _TokenTypeName[398:407],
2016: _TokenTypeName[407:417],
2017: _TokenTypeName[417:429],
2018: _TokenTypeName[429:436],
2019: _TokenTypeName[436:448],
2020: _TokenTypeName[448:469],
2021: _TokenTypeName[469:486],
2022: _TokenTypeName[486:504],
2023: _TokenTypeName[504:524],
2024: _TokenTypeName[524:541],
2002: _TokenTypeName[239:248],
2003: _TokenTypeName[248:260],
2004: _TokenTypeName[260:273],
2005: _TokenTypeName[273:283],
2006: _TokenTypeName[283:296],
2007: _TokenTypeName[296:307],
2008: _TokenTypeName[307:316],
2009: _TokenTypeName[316:329],
2010: _TokenTypeName[329:341],
2011: _TokenTypeName[341:350],
2012: _TokenTypeName[350:360],
2013: _TokenTypeName[360:372],
2014: _TokenTypeName[372:379],
2100: _TokenTypeName[379:390],
2101: _TokenTypeName[390:407],
2200: _TokenTypeName[407:419],
2201: _TokenTypeName[419:440],
2202: _TokenTypeName[440:457],
2203: _TokenTypeName[457:475],
2204: _TokenTypeName[475:495],
2205: _TokenTypeName[495:512],
2300: _TokenTypeName[512:524],
2301: _TokenTypeName[524:541],
3000: _TokenTypeName[541:548],
3001: _TokenTypeName[548:559],
3002: _TokenTypeName[559:571],
@@ -149,29 +149,29 @@ func _TokenTypeNoOp() {
_ = x[KeywordType-(1006)]
_ = x[Name-(2000)]
_ = x[NameAttribute-(2001)]
_ = x[NameBuiltin-(2002)]
_ = x[NameBuiltinPseudo-(2003)]
_ = x[NameClass-(2004)]
_ = x[NameConstant-(2005)]
_ = x[NameDecorator-(2006)]
_ = x[NameEntity-(2007)]
_ = x[NameException-(2008)]
_ = x[NameFunction-(2009)]
_ = x[NameFunctionMagic-(2010)]
_ = x[NameKeyword-(2011)]
_ = x[NameLabel-(2012)]
_ = x[NameNamespace-(2013)]
_ = x[NameOperator-(2014)]
_ = x[NameOther-(2015)]
_ = x[NamePseudo-(2016)]
_ = x[NameProperty-(2017)]
_ = x[NameTag-(2018)]
_ = x[NameVariable-(2019)]
_ = x[NameVariableAnonymous-(2020)]
_ = x[NameVariableClass-(2021)]
_ = x[NameVariableGlobal-(2022)]
_ = x[NameVariableInstance-(2023)]
_ = x[NameVariableMagic-(2024)]
_ = x[NameClass-(2002)]
_ = x[NameConstant-(2003)]
_ = x[NameDecorator-(2004)]
_ = x[NameEntity-(2005)]
_ = x[NameException-(2006)]
_ = x[NameKeyword-(2007)]
_ = x[NameLabel-(2008)]
_ = x[NameNamespace-(2009)]
_ = x[NameOperator-(2010)]
_ = x[NameOther-(2011)]
_ = x[NamePseudo-(2012)]
_ = x[NameProperty-(2013)]
_ = x[NameTag-(2014)]
_ = x[NameBuiltin-(2100)]
_ = x[NameBuiltinPseudo-(2101)]
_ = x[NameVariable-(2200)]
_ = x[NameVariableAnonymous-(2201)]
_ = x[NameVariableClass-(2202)]
_ = x[NameVariableGlobal-(2203)]
_ = x[NameVariableInstance-(2204)]
_ = x[NameVariableMagic-(2205)]
_ = x[NameFunction-(2300)]
_ = x[NameFunctionMagic-(2301)]
_ = x[Literal-(3000)]
_ = x[LiteralDate-(3001)]
_ = x[LiteralOther-(3002)]
@@ -228,7 +228,7 @@ func _TokenTypeNoOp() {
_ = x[TextPunctuation-(8003)]
}
var _TokenTypeValues = []TokenType{Ignore, None, Other, Error, CodeLine, LineLink, LineTableTD, LineTable, LineHighlight, LineNumbersTable, LineNumbers, Line, PreWrapper, Background, EOFType, Keyword, KeywordConstant, KeywordDeclaration, KeywordNamespace, KeywordPseudo, KeywordReserved, KeywordType, Name, NameAttribute, NameBuiltin, NameBuiltinPseudo, NameClass, NameConstant, NameDecorator, NameEntity, NameException, NameFunction, NameFunctionMagic, NameKeyword, NameLabel, NameNamespace, NameOperator, NameOther, NamePseudo, NameProperty, NameTag, NameVariable, NameVariableAnonymous, NameVariableClass, NameVariableGlobal, NameVariableInstance, NameVariableMagic, Literal, LiteralDate, LiteralOther, LiteralString, LiteralStringAffix, LiteralStringAtom, LiteralStringBacktick, LiteralStringBoolean, LiteralStringChar, LiteralStringDelimiter, LiteralStringDoc, LiteralStringDouble, LiteralStringEscape, LiteralStringHeredoc, LiteralStringInterpol, LiteralStringName, LiteralStringOther, LiteralStringRegex, LiteralStringSingle, LiteralStringSymbol, LiteralNumber, LiteralNumberBin, LiteralNumberFloat, LiteralNumberHex, LiteralNumberInteger, LiteralNumberIntegerLong, LiteralNumberOct, LiteralNumberByte, Operator, OperatorWord, Punctuation, Comment, CommentHashbang, CommentMultiline, CommentSingle, CommentSpecial, CommentPreproc, CommentPreprocFile, Generic, GenericDeleted, GenericEmph, GenericError, GenericHeading, GenericInserted, GenericOutput, GenericPrompt, GenericStrong, GenericSubheading, GenericTraceback, GenericUnderline, Text, TextWhitespace, TextSymbol, TextPunctuation}
var _TokenTypeValues = []TokenType{Ignore, None, Other, Error, CodeLine, LineLink, LineTableTD, LineTable, LineHighlight, LineNumbersTable, LineNumbers, Line, PreWrapper, Background, EOFType, Keyword, KeywordConstant, KeywordDeclaration, KeywordNamespace, KeywordPseudo, KeywordReserved, KeywordType, Name, NameAttribute, NameClass, NameConstant, NameDecorator, NameEntity, NameException, NameKeyword, NameLabel, NameNamespace, NameOperator, NameOther, NamePseudo, NameProperty, NameTag, NameBuiltin, NameBuiltinPseudo, NameVariable, NameVariableAnonymous, NameVariableClass, NameVariableGlobal, NameVariableInstance, NameVariableMagic, NameFunction, NameFunctionMagic, Literal, LiteralDate, LiteralOther, LiteralString, LiteralStringAffix, LiteralStringAtom, LiteralStringBacktick, LiteralStringBoolean, LiteralStringChar, LiteralStringDelimiter, LiteralStringDoc, LiteralStringDouble, LiteralStringEscape, LiteralStringHeredoc, LiteralStringInterpol, LiteralStringName, LiteralStringOther, LiteralStringRegex, LiteralStringSingle, LiteralStringSymbol, LiteralNumber, LiteralNumberBin, LiteralNumberFloat, LiteralNumberHex, LiteralNumberInteger, LiteralNumberIntegerLong, LiteralNumberOct, LiteralNumberByte, Operator, OperatorWord, Punctuation, Comment, CommentHashbang, CommentMultiline, CommentSingle, CommentSpecial, CommentPreproc, CommentPreprocFile, Generic, GenericDeleted, GenericEmph, GenericError, GenericHeading, GenericInserted, GenericOutput, GenericPrompt, GenericStrong, GenericSubheading, GenericTraceback, GenericUnderline, Text, TextWhitespace, TextSymbol, TextPunctuation}
var _TokenTypeNameToValueMap = map[string]TokenType{
_TokenTypeName[0:6]: Ignore,
@@ -279,52 +279,52 @@ var _TokenTypeNameToValueMap = map[string]TokenType{
_TokenTypeLowerName[222:226]: Name,
_TokenTypeName[226:239]: NameAttribute,
_TokenTypeLowerName[226:239]: NameAttribute,
_TokenTypeName[239:250]: NameBuiltin,
_TokenTypeLowerName[239:250]: NameBuiltin,
_TokenTypeName[250:267]: NameBuiltinPseudo,
_TokenTypeLowerName[250:267]: NameBuiltinPseudo,
_TokenTypeName[267:276]: NameClass,
_TokenTypeLowerName[267:276]: NameClass,
_TokenTypeName[276:288]: NameConstant,
_TokenTypeLowerName[276:288]: NameConstant,
_TokenTypeName[288:301]: NameDecorator,
_TokenTypeLowerName[288:301]: NameDecorator,
_TokenTypeName[301:311]: NameEntity,
_TokenTypeLowerName[301:311]: NameEntity,
_TokenTypeName[311:324]: NameException,
_TokenTypeLowerName[311:324]: NameException,
_TokenTypeName[324:336]: NameFunction,
_TokenTypeLowerName[324:336]: NameFunction,
_TokenTypeName[336:353]: NameFunctionMagic,
_TokenTypeLowerName[336:353]: NameFunctionMagic,
_TokenTypeName[353:364]: NameKeyword,
_TokenTypeLowerName[353:364]: NameKeyword,
_TokenTypeName[364:373]: NameLabel,
_TokenTypeLowerName[364:373]: NameLabel,
_TokenTypeName[373:386]: NameNamespace,
_TokenTypeLowerName[373:386]: NameNamespace,
_TokenTypeName[386:398]: NameOperator,
_TokenTypeLowerName[386:398]: NameOperator,
_TokenTypeName[398:407]: NameOther,
_TokenTypeLowerName[398:407]: NameOther,
_TokenTypeName[407:417]: NamePseudo,
_TokenTypeLowerName[407:417]: NamePseudo,
_TokenTypeName[417:429]: NameProperty,
_TokenTypeLowerName[417:429]: NameProperty,
_TokenTypeName[429:436]: NameTag,
_TokenTypeLowerName[429:436]: NameTag,
_TokenTypeName[436:448]: NameVariable,
_TokenTypeLowerName[436:448]: NameVariable,
_TokenTypeName[448:469]: NameVariableAnonymous,
_TokenTypeLowerName[448:469]: NameVariableAnonymous,
_TokenTypeName[469:486]: NameVariableClass,
_TokenTypeLowerName[469:486]: NameVariableClass,
_TokenTypeName[486:504]: NameVariableGlobal,
_TokenTypeLowerName[486:504]: NameVariableGlobal,
_TokenTypeName[504:524]: NameVariableInstance,
_TokenTypeLowerName[504:524]: NameVariableInstance,
_TokenTypeName[524:541]: NameVariableMagic,
_TokenTypeLowerName[524:541]: NameVariableMagic,
_TokenTypeName[239:248]: NameClass,
_TokenTypeLowerName[239:248]: NameClass,
_TokenTypeName[248:260]: NameConstant,
_TokenTypeLowerName[248:260]: NameConstant,
_TokenTypeName[260:273]: NameDecorator,
_TokenTypeLowerName[260:273]: NameDecorator,
_TokenTypeName[273:283]: NameEntity,
_TokenTypeLowerName[273:283]: NameEntity,
_TokenTypeName[283:296]: NameException,
_TokenTypeLowerName[283:296]: NameException,
_TokenTypeName[296:307]: NameKeyword,
_TokenTypeLowerName[296:307]: NameKeyword,
_TokenTypeName[307:316]: NameLabel,
_TokenTypeLowerName[307:316]: NameLabel,
_TokenTypeName[316:329]: NameNamespace,
_TokenTypeLowerName[316:329]: NameNamespace,
_TokenTypeName[329:341]: NameOperator,
_TokenTypeLowerName[329:341]: NameOperator,
_TokenTypeName[341:350]: NameOther,
_TokenTypeLowerName[341:350]: NameOther,
_TokenTypeName[350:360]: NamePseudo,
_TokenTypeLowerName[350:360]: NamePseudo,
_TokenTypeName[360:372]: NameProperty,
_TokenTypeLowerName[360:372]: NameProperty,
_TokenTypeName[372:379]: NameTag,
_TokenTypeLowerName[372:379]: NameTag,
_TokenTypeName[379:390]: NameBuiltin,
_TokenTypeLowerName[379:390]: NameBuiltin,
_TokenTypeName[390:407]: NameBuiltinPseudo,
_TokenTypeLowerName[390:407]: NameBuiltinPseudo,
_TokenTypeName[407:419]: NameVariable,
_TokenTypeLowerName[407:419]: NameVariable,
_TokenTypeName[419:440]: NameVariableAnonymous,
_TokenTypeLowerName[419:440]: NameVariableAnonymous,
_TokenTypeName[440:457]: NameVariableClass,
_TokenTypeLowerName[440:457]: NameVariableClass,
_TokenTypeName[457:475]: NameVariableGlobal,
_TokenTypeLowerName[457:475]: NameVariableGlobal,
_TokenTypeName[475:495]: NameVariableInstance,
_TokenTypeLowerName[475:495]: NameVariableInstance,
_TokenTypeName[495:512]: NameVariableMagic,
_TokenTypeLowerName[495:512]: NameVariableMagic,
_TokenTypeName[512:524]: NameFunction,
_TokenTypeLowerName[512:524]: NameFunction,
_TokenTypeName[524:541]: NameFunctionMagic,
_TokenTypeLowerName[524:541]: NameFunctionMagic,
_TokenTypeName[541:548]: Literal,
_TokenTypeLowerName[541:548]: Literal,
_TokenTypeName[548:559]: LiteralDate,
@@ -460,28 +460,28 @@ var _TokenTypeNames = []string{
_TokenTypeName[211:222],
_TokenTypeName[222:226],
_TokenTypeName[226:239],
_TokenTypeName[239:250],
_TokenTypeName[250:267],
_TokenTypeName[267:276],
_TokenTypeName[276:288],
_TokenTypeName[288:301],
_TokenTypeName[301:311],
_TokenTypeName[311:324],
_TokenTypeName[324:336],
_TokenTypeName[336:353],
_TokenTypeName[353:364],
_TokenTypeName[364:373],
_TokenTypeName[373:386],
_TokenTypeName[386:398],
_TokenTypeName[398:407],
_TokenTypeName[407:417],
_TokenTypeName[417:429],
_TokenTypeName[429:436],
_TokenTypeName[436:448],
_TokenTypeName[448:469],
_TokenTypeName[469:486],
_TokenTypeName[486:504],
_TokenTypeName[504:524],
_TokenTypeName[239:248],
_TokenTypeName[248:260],
_TokenTypeName[260:273],
_TokenTypeName[273:283],
_TokenTypeName[283:296],
_TokenTypeName[296:307],
_TokenTypeName[307:316],
_TokenTypeName[316:329],
_TokenTypeName[329:341],
_TokenTypeName[341:350],
_TokenTypeName[350:360],
_TokenTypeName[360:372],
_TokenTypeName[372:379],
_TokenTypeName[379:390],
_TokenTypeName[390:407],
_TokenTypeName[407:419],
_TokenTypeName[419:440],
_TokenTypeName[440:457],
_TokenTypeName[457:475],
_TokenTypeName[475:495],
_TokenTypeName[495:512],
_TokenTypeName[512:524],
_TokenTypeName[524:541],
_TokenTypeName[541:548],
_TokenTypeName[548:559],
+17 -5
View File
@@ -62,15 +62,11 @@ const (
const (
Name TokenType = 2000 + iota
NameAttribute
NameBuiltin
NameBuiltinPseudo
NameClass
NameConstant
NameDecorator
NameEntity
NameException
NameFunction
NameFunctionMagic
NameKeyword
NameLabel
NameNamespace
@@ -79,7 +75,17 @@ const (
NamePseudo
NameProperty
NameTag
NameVariable
)
// Builtin names.
const (
NameBuiltin TokenType = 2100 + iota
NameBuiltinPseudo
)
// Variable names.
const (
NameVariable TokenType = 2200 + iota
NameVariableAnonymous
NameVariableClass
NameVariableGlobal
@@ -87,6 +93,12 @@ const (
NameVariableMagic
)
// Function names.
const (
NameFunction TokenType = 2300 + iota
NameFunctionMagic
)
// Literals.
const (
Literal TokenType = 3000 + iota
-3
View File
@@ -1,3 +0,0 @@
/debug
/.vscode
/.idea
-33
View File
@@ -1,33 +0,0 @@
linters:
enable:
- revive
- govet
- unconvert
- megacheck
- gas
- gocyclo
- dupl
- misspell
- unparam
- unused
- typecheck
- ineffassign
- stylecheck
- gochecknoinits
- exportloopref
- gocritic
- nakedret
- gosimple
- prealloc
fast: false
disable-all: true
issues:
exclude-rules:
- path: _test\.go
linters:
- dupl
- text: "Errors unhandled"
linters:
- gosec
exclude-use-default: false
-217
View File
@@ -1,217 +0,0 @@
[![GoDoc](https://godoc.org/github.com/didip/tollbooth?status.svg)](http://godoc.org/github.com/didip/tollbooth)
[![license](http://img.shields.io/badge/license-MIT-red.svg?style=flat)](https://raw.githubusercontent.com/didip/tollbooth/master/LICENSE)
## Tollbooth
This is a generic middleware to rate-limit HTTP requests.
**NOTE 1:** This library is considered finished.
**NOTE 2:** Major version changes are backward-incompatible. `v2.0.0` streamlines the ugliness of the old API.
## Versions
**v1.0.0:** This version maintains the old API but all the thirdparty modules are moved to their own repo.
**v2.x.x:** Brand-new API for the sake of code cleanup, thread safety, & auto-expiring data structures.
**v3.x.x:** Apparently we have been using golang.org/x/time/rate incorrectly. See issue #48. It always limits X number per 1 second. The time duration is not changeable, so it does not make sense to pass TTL to tollbooth.
**v4.x.x:** Float64 for max requests per second
**v5.x.x:** go.mod and go.sum
**v6.x.x:** Replaced `go-cache` with `github.com/go-pkgz/expirable-cache` because `go-cache` leaks goroutines.
**v7.x.x:** Replaced `time/rate` with `embedded time/rate` so that we can support more rate limit headers.
**v8.x.x:** Address `RemoteIP` vulnerability concern by replacing `SetIPLookups` with `SetIPLookup`, an explicit way to pick the IP address.
## Five Minute Tutorial
```go
package main
import (
"net/http"
"github.com/didip/tollbooth/v8"
"github.com/didip/tollbooth/v8/limiter"
)
func HelloHandler(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Hello, World!"))
}
func main() {
// Create a request limiter per handler.
lmt := tollbooth.NewLimiter(1, nil)
// New in version >= 8, you must explicitly define how to pick the IP address.
lmt.SetIPLookup(limiter.IPLookup{
Name: "X-Real-IP",
IndexFromRight: 0,
})
http.Handle("/", tollbooth.LimitFuncHandler(lmt, HelloHandler))
http.ListenAndServe(":12345", nil)
}
```
## Features
1. Rate-limit by request's remote IP, path, methods, custom headers, & basic auth usernames.
```go
import (
"time"
"github.com/didip/tollbooth/v8"
"github.com/didip/tollbooth/v8/limiter"
)
lmt := tollbooth.NewLimiter(1, nil)
// or create a limiter with expirable token buckets
// This setting means:
// create a 1 request/second limiter and
// every token bucket in it will expire 1 hour after it was initially set.
lmt = tollbooth.NewLimiter(1, &limiter.ExpirableOptions{DefaultExpirationTTL: time.Hour})
// New in version >= 8, you must explicitly define how to pick the IP address.
// If IP address cannot be found, rate limiter will not be activated.
lmt.SetIPLookup(limiter.IPLookup{
// The name of lookup method.
// Possible options are: RemoteAddr, X-Forwarded-For, X-Real-IP, CF-Connecting-IP
// All other headers are considered unknown and will be ignored.
Name: "X-Real-IP",
// The index position to pick the ip address from a comma separated list.
// The index goes from right to left.
//
// When there are multiple of the same headers,
// we will concat them together in the order of first to last seen.
// And then we pick the IP using this index position.
IndexFromRight: 0,
})
// In version >= 8, lmt.SetIPLookups and lmt.GetIPLookups are removed.
// Limit only GET and POST requests.
lmt.SetMethods([]string{"GET", "POST"})
// Limit based on basic auth usernames.
// You add them on-load, or later as you handle requests.
lmt.SetBasicAuthUsers([]string{"bob", "jane", "didip", "vip"})
// You can remove them later as well.
lmt.RemoveBasicAuthUsers([]string{"vip"})
// Limit request headers containing certain values.
// You add them on-load, or later as you handle requests.
lmt.SetHeader("X-Access-Token", []string{"abc123", "xyz098"})
// You can remove all entries at once.
lmt.RemoveHeader("X-Access-Token")
// Or remove specific ones.
lmt.RemoveHeaderEntries("X-Access-Token", []string{"limitless-token"})
// By the way, the setters are chainable. Example:
lmt.SetMethods([]string{"GET", "POST"}).
SetBasicAuthUsers([]string{"sansa"}).
SetBasicAuthUsers([]string{"tyrion"})
```
2. Compose your own middleware by using `LimitByKeys()`.
3. Header entries and basic auth users can expire over time (to conserve memory).
```go
import "time"
lmt := tollbooth.NewLimiter(1, nil)
// Set a custom expiration TTL for token bucket.
lmt.SetTokenBucketExpirationTTL(time.Hour)
// Set a custom expiration TTL for basic auth users.
lmt.SetBasicAuthExpirationTTL(time.Hour)
// Set a custom expiration TTL for header entries.
lmt.SetHeaderEntryExpirationTTL(time.Hour)
```
4. Upon rejection, the following HTTP response headers are available to users:
* `X-Rate-Limit-Limit` The maximum request limit.
* `X-Rate-Limit-Duration` The rate-limiter duration.
* `X-Rate-Limit-Request-Forwarded-For` The rejected request `X-Forwarded-For`.
* `X-Rate-Limit-Request-Remote-Addr` The rejected request `RemoteAddr`.
Upon both success and rejection [RateLimit](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers) headers are sent:
* `RateLimit-Limit` The maximum request limit within the time window (1s).
* `RateLimit-Reset` The rate-limiter time window duration in seconds (always 1s).
* `RateLimit-Remaining` The remaining tokens.
5. Customize your own message or function when limit is reached.
```go
lmt := tollbooth.NewLimiter(1, nil)
// New in version >= 8, you must explicitly define how to pick the IP address.
lmt.SetIPLookup(limiter.IPLookup{
Name: "X-Forwarded-For",
IndexFromRight: 0,
})
// Set a custom message.
lmt.SetMessage("You have reached maximum request limit.")
// Set a custom content-type.
lmt.SetMessageContentType("text/plain; charset=utf-8")
// Set a custom function for rejection.
lmt.SetOnLimitReached(func(w http.ResponseWriter, r *http.Request) { fmt.Println("A request was rejected") })
```
6. Tollbooth does not require external storage since it uses an algorithm called [Token Bucket](http://en.wikipedia.org/wiki/Token_bucket) [(Go library: golang.org/x/time/rate)](https://godoc.org/golang.org/x/time/rate).
## Other Web Frameworks
Sometimes, other frameworks require a little bit of shim to use Tollbooth. These shims below are contributed by the community, so I make no promises on how well they work. The one I am familiar with are: Chi, Gin, and Negroni.
* [Chi](https://github.com/didip/tollbooth_chi)
* [Echo](https://github.com/didip/tollbooth_echo)
* [FastHTTP](https://github.com/didip/tollbooth_fasthttp)
* [Gin](https://github.com/didip/tollbooth_gin)
* [GoRestful](https://github.com/didip/tollbooth_gorestful)
* [HTTPRouter](https://github.com/didip/tollbooth_httprouter)
* [Iris](https://github.com/didip/tollbooth_iris)
* [Negroni](https://github.com/didip/tollbooth_negroni)
## My other Go libraries
* [ErrStack](https://github.com/didip/errstack): A small library to combine errors and also display filename and line number.
* [Stopwatch](https://github.com/didip/stopwatch): A small library to measure latency of things. Useful if you want to report latency data to Graphite.
* [LaborUnion](https://github.com/didip/laborunion): A dynamic worker pool library.
* [Gomet](https://github.com/didip/gomet): Simple HTTP client & server long poll library for Go. Useful for receiving live updates without needing Websocket.
## Contributions
Before sending a PR with code changes, please make sure altered code is covered with tests which are passing, and that golangci-lint shows no errors.
To check the linter output, [install it](https://golangci-lint.run/usage/install/#local-installation) and then run `golangci-lint run` in the root directory of the repository.
-15
View File
@@ -1,15 +0,0 @@
// Package errors provide data structure for errors.
package errors
import "fmt"
// HTTPError is an error struct that returns both message and status code.
type HTTPError struct {
Message string
StatusCode int
}
// Error returns error message.
func (httperror *HTTPError) Error() string {
return fmt.Sprintf("%v: %v", httperror.StatusCode, httperror.Message)
}
-3
View File
@@ -1,3 +0,0 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.
@@ -1,3 +0,0 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.
-27
View File
@@ -1,27 +0,0 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-22
View File
@@ -1,22 +0,0 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.
-396
View File
@@ -1,396 +0,0 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package rate provides a rate limiter.
package rate
import (
"context"
"fmt"
"math"
"sync"
"time"
)
// Limit defines the maximum frequency of some events.
// Limit is represented as number of events per second.
// A zero Limit allows no events.
type Limit float64
// Inf is the infinite rate limit; it allows all events (even if burst is zero).
const Inf = Limit(math.MaxFloat64)
// Every converts a minimum time interval between events to a Limit.
func Every(interval time.Duration) Limit {
if interval <= 0 {
return Inf
}
return 1 / Limit(interval.Seconds())
}
// A Limiter controls how frequently events are allowed to happen.
// It implements a "token bucket" of size b, initially full and refilled
// at rate r tokens per second.
// Informally, in any large enough time interval, the Limiter limits the
// rate to r tokens per second, with a maximum burst size of b events.
// As a special case, if r == Inf (the infinite rate), b is ignored.
// See https://en.wikipedia.org/wiki/Token_bucket for more about token buckets.
//
// The zero value is a valid Limiter, but it will reject all events.
// Use NewLimiter to create non-zero Limiters.
//
// Limiter has three main methods, Allow, Reserve, and Wait.
// Most callers should use Wait.
//
// Each of the three methods consumes a single token.
// They differ in their behavior when no token is available.
// If no token is available, Allow returns false.
// If no token is available, Reserve returns a reservation for a future token
// and the amount of time the caller must wait before using it.
// If no token is available, Wait blocks until one can be obtained
// or its associated context.Context is canceled.
//
// The methods AllowN, ReserveN, and WaitN consume n tokens.
type Limiter struct {
mu sync.Mutex
limit Limit
burst int
tokens float64
// last is the last time the limiter's tokens field was updated
last time.Time
// lastEvent is the latest time of a rate-limited event (past or future)
lastEvent time.Time
}
// Limit returns the maximum overall event rate.
func (lim *Limiter) Limit() Limit {
lim.mu.Lock()
defer lim.mu.Unlock()
return lim.limit
}
// Burst returns the maximum burst size. Burst is the maximum number of tokens
// that can be consumed in a single call to Allow, Reserve, or Wait, so higher
// Burst values allow more events to happen at once.
// A zero Burst allows no events, unless limit == Inf.
func (lim *Limiter) Burst() int {
lim.mu.Lock()
defer lim.mu.Unlock()
return lim.burst
}
// NewLimiter returns a new Limiter that allows events up to rate r and permits
// bursts of at most b tokens.
func NewLimiter(r Limit, b int) *Limiter {
return &Limiter{
limit: r,
burst: b,
}
}
// Allow is shorthand for AllowN(time.Now(), 1).
func (lim *Limiter) Allow() bool {
return lim.AllowN(time.Now(), 1)
}
// TokensAt returns the number of tokens available for the given time.
func (lim *Limiter) TokensAt(t time.Time) float64 {
lim.mu.Lock()
_, _, tokens := lim.advance(t) // does not mutate lim
lim.mu.Unlock()
return tokens
}
// AllowN reports whether n events may happen at time now.
// Use this method if you intend to drop / skip events that exceed the rate limit.
// Otherwise use Reserve or Wait.
func (lim *Limiter) AllowN(now time.Time, n int) bool {
return lim.reserveN(now, n, 0).ok
}
// A Reservation holds information about events that are permitted by a Limiter to happen after a delay.
// A Reservation may be canceled, which may enable the Limiter to permit additional events.
type Reservation struct {
ok bool
lim *Limiter
tokens int
timeToAct time.Time
// This is the Limit at reservation time, it can change later.
limit Limit
}
// OK returns whether the limiter can provide the requested number of tokens
// within the maximum wait time. If OK is false, Delay returns InfDuration, and
// Cancel does nothing.
func (r *Reservation) OK() bool {
return r.ok
}
// Delay is shorthand for DelayFrom(time.Now()).
func (r *Reservation) Delay() time.Duration {
return r.DelayFrom(time.Now())
}
// InfDuration is the duration returned by Delay when a Reservation is not OK.
const InfDuration = time.Duration(1<<63 - 1)
// DelayFrom returns the duration for which the reservation holder must wait
// before taking the reserved action. Zero duration means act immediately.
// InfDuration means the limiter cannot grant the tokens requested in this
// Reservation within the maximum wait time.
func (r *Reservation) DelayFrom(now time.Time) time.Duration {
if !r.ok {
return InfDuration
}
delay := r.timeToAct.Sub(now)
if delay < 0 {
return 0
}
return delay
}
// Cancel is shorthand for CancelAt(time.Now()).
func (r *Reservation) Cancel() {
r.CancelAt(time.Now())
}
// CancelAt indicates that the reservation holder will not perform the reserved action
// and reverses the effects of this Reservation on the rate limit as much as possible,
// considering that other reservations may have already been made.
func (r *Reservation) CancelAt(now time.Time) {
if !r.ok {
return
}
r.lim.mu.Lock()
defer r.lim.mu.Unlock()
if r.lim.limit == Inf || r.tokens == 0 || r.timeToAct.Before(now) {
return
}
// calculate tokens to restore
// The duration between lim.lastEvent and r.timeToAct tells us how many tokens were reserved
// after r was obtained. These tokens should not be restored.
restoreTokens := float64(r.tokens) - r.limit.tokensFromDuration(r.lim.lastEvent.Sub(r.timeToAct))
if restoreTokens <= 0 {
return
}
// advance time to now
now, _, tokens := r.lim.advance(now)
// calculate new number of tokens
tokens += restoreTokens
if burst := float64(r.lim.burst); tokens > burst {
tokens = burst
}
// update state
r.lim.last = now
r.lim.tokens = tokens
if r.timeToAct == r.lim.lastEvent {
prevEvent := r.timeToAct.Add(r.limit.durationFromTokens(float64(-r.tokens)))
if !prevEvent.Before(now) {
r.lim.lastEvent = prevEvent
}
}
}
// Reserve is shorthand for ReserveN(time.Now(), 1).
func (lim *Limiter) Reserve() *Reservation {
return lim.ReserveN(time.Now(), 1)
}
// ReserveN returns a Reservation that indicates how long the caller must wait before n events happen.
// The Limiter takes this Reservation into account when allowing future events.
// The returned Reservations OK() method returns false if n exceeds the Limiter's burst size.
// Usage example:
// r := lim.ReserveN(time.Now(), 1)
// if !r.OK() {
// // Not allowed to act! Did you remember to set lim.burst to be > 0 ?
// return
// }
// time.Sleep(r.Delay())
// Act()
// Use this method if you wish to wait and slow down in accordance with the rate limit without dropping events.
// If you need to respect a deadline or cancel the delay, use Wait instead.
// To drop or skip events exceeding rate limit, use Allow instead.
func (lim *Limiter) ReserveN(now time.Time, n int) *Reservation {
r := lim.reserveN(now, n, InfDuration)
return &r
}
// Wait is shorthand for WaitN(ctx, 1).
func (lim *Limiter) Wait(ctx context.Context) (err error) {
return lim.WaitN(ctx, 1)
}
// WaitN blocks until lim permits n events to happen.
// It returns an error if n exceeds the Limiter's burst size, the Context is
// canceled, or the expected wait time exceeds the Context's Deadline.
// The burst limit is ignored if the rate limit is Inf.
func (lim *Limiter) WaitN(ctx context.Context, n int) (err error) {
lim.mu.Lock()
burst := lim.burst
limit := lim.limit
lim.mu.Unlock()
if n > burst && limit != Inf {
return fmt.Errorf("rate: Wait(n=%d) exceeds limiter's burst %d", n, burst)
}
// Check if ctx is already cancelled
select {
case <-ctx.Done():
return ctx.Err()
default:
}
// Determine wait limit
now := time.Now()
waitLimit := InfDuration
if deadline, ok := ctx.Deadline(); ok {
waitLimit = deadline.Sub(now)
}
// Reserve
r := lim.reserveN(now, n, waitLimit)
if !r.ok {
return fmt.Errorf("rate: Wait(n=%d) would exceed context deadline", n)
}
// Wait if necessary
delay := r.DelayFrom(now)
if delay == 0 {
return nil
}
t := time.NewTimer(delay)
defer t.Stop()
select {
case <-t.C:
// We can proceed.
return nil
case <-ctx.Done():
// Context was canceled before we could proceed. Cancel the
// reservation, which may permit other events to proceed sooner.
r.Cancel()
return ctx.Err()
}
}
// SetLimit is shorthand for SetLimitAt(time.Now(), newLimit).
func (lim *Limiter) SetLimit(newLimit Limit) {
lim.SetLimitAt(time.Now(), newLimit)
}
// SetLimitAt sets a new Limit for the limiter. The new Limit, and Burst, may be violated
// or underutilized by those which reserved (using Reserve or Wait) but did not yet act
// before SetLimitAt was called.
func (lim *Limiter) SetLimitAt(now time.Time, newLimit Limit) {
lim.mu.Lock()
defer lim.mu.Unlock()
now, _, tokens := lim.advance(now)
lim.last = now
lim.tokens = tokens
lim.limit = newLimit
}
// SetBurst is shorthand for SetBurstAt(time.Now(), newBurst).
func (lim *Limiter) SetBurst(newBurst int) {
lim.SetBurstAt(time.Now(), newBurst)
}
// SetBurstAt sets a new burst size for the limiter.
func (lim *Limiter) SetBurstAt(now time.Time, newBurst int) {
lim.mu.Lock()
defer lim.mu.Unlock()
now, _, tokens := lim.advance(now)
lim.last = now
lim.tokens = tokens
lim.burst = newBurst
}
// reserveN is a helper method for AllowN, ReserveN, and WaitN.
// maxFutureReserve specifies the maximum reservation wait duration allowed.
// reserveN returns Reservation, not *Reservation, to avoid allocation in AllowN and WaitN.
func (lim *Limiter) reserveN(now time.Time, n int, maxFutureReserve time.Duration) Reservation {
lim.mu.Lock()
if lim.limit == Inf {
lim.mu.Unlock()
return Reservation{
ok: true,
lim: lim,
tokens: n,
timeToAct: now,
}
}
now, last, tokens := lim.advance(now)
// Calculate the remaining number of tokens resulting from the request.
tokens -= float64(n)
// Calculate the wait duration
var waitDuration time.Duration
if tokens < 0 {
waitDuration = lim.limit.durationFromTokens(-tokens)
}
// Decide result
ok := n <= lim.burst && waitDuration <= maxFutureReserve
// Prepare reservation
r := Reservation{
ok: ok,
lim: lim,
limit: lim.limit,
}
if ok {
r.tokens = n
r.timeToAct = now.Add(waitDuration)
}
// Update state
if ok {
lim.last = now
lim.tokens = tokens
lim.lastEvent = r.timeToAct
} else {
lim.last = last
}
lim.mu.Unlock()
return r
}
// advance calculates and returns an updated state for lim resulting from the passage of time.
// lim is not changed.
// advance requires that lim.mu is held.
func (lim *Limiter) advance(now time.Time) (newNow time.Time, newLast time.Time, newTokens float64) {
last := lim.last
if now.Before(last) {
last = now
}
// Calculate the new number of tokens, due to time that passed.
elapsed := now.Sub(last)
delta := lim.limit.tokensFromDuration(elapsed)
tokens := lim.tokens + delta
if burst := float64(lim.burst); tokens > burst {
tokens = burst
}
return now, last, tokens
}
// durationFromTokens is a unit conversion function from the number of tokens to the duration
// of time it takes to accumulate them at a rate of limit tokens per second.
func (limit Limit) durationFromTokens(tokens float64) time.Duration {
seconds := tokens / float64(limit)
return time.Duration(float64(time.Second) * seconds)
}
// tokensFromDuration is a unit conversion function from a time duration to the number of tokens
// which could be accumulated during that duration at a rate of limit tokens per second.
func (limit Limit) tokensFromDuration(d time.Duration) float64 {
return d.Seconds() * float64(limit)
}
-100
View File
@@ -1,100 +0,0 @@
// Package libstring provides various string related functions.
package libstring
import (
"net"
"net/http"
"strings"
"github.com/didip/tollbooth/v8/limiter"
)
// StringInSlice finds needle in a slice of strings.
func StringInSlice(sliceString []string, needle string) bool {
for _, b := range sliceString {
if b == needle {
return true
}
}
return false
}
// RemoteIPFromIPLookup picks an ip address explicitly from limiter.IPLookup criteria.
// This function is intended to replace RemoteIP function.
func RemoteIPFromIPLookup(ipLookup limiter.IPLookup, r *http.Request) string {
switch ipLookup.Name {
case "RemoteAddr":
// 1. Cover the basic use cases for both ipv4 and ipv6
ip, _, err := net.SplitHostPort(r.RemoteAddr)
if err != nil {
// 2. Upon error, just return the remote addr.
return r.RemoteAddr
}
return ip
case "X-Forwarded-For", "X-Real-IP", "CF-Connecting-IP":
ipAddrListCommaSeparated := r.Header.Values(ipLookup.Name)
ipAddrCommaSeparated := strings.Join(ipAddrListCommaSeparated, ",")
ips := strings.Split(ipAddrCommaSeparated, ",")
for i, p := range ips {
ips[i] = strings.TrimSpace(p)
}
ipIndex := len(ips) - 1 - ipLookup.IndexFromRight
if ipIndex < 0 {
ipIndex = 0
}
return ips[ipIndex]
}
return ""
}
// CanonicalizeIP returns a form of ip suitable for comparison to other IPs.
// For IPv4 addresses, this is simply the whole string.
// For IPv6 addresses, this is the /64 prefix.
func CanonicalizeIP(ip string) string {
isIPv6 := false
// This is how net.ParseIP decides if an address is IPv6
// https://cs.opensource.google/go/go/+/refs/tags/go1.17.7:src/net/ip.go;l=704
for i := 0; !isIPv6 && i < len(ip); i++ {
switch ip[i] {
case '.':
// IPv4
return ip
case ':':
// IPv6
isIPv6 = true
}
}
if !isIPv6 {
// Not an IP address at all
return ip
}
// By default, the string representation of a net.IPNet (masked IP address) is just
// "full_address/mask_bits". But using that will result in different addresses with
// the same /64 prefix comparing differently. So we need to zero out the last 64 bits
// so that all IPs in the same prefix will be the same.
//
// Note: When 1.18 is the minimum Go version, this can be written more cleanly like:
// netip.PrefixFrom(netip.MustParseAddr(ipv6), 64).Masked().Addr().String()
// (With appropriate error checking.)
ipv6 := net.ParseIP(ip)
if ipv6 == nil {
return ip
}
const bytesToZero = (128 - 64) / 8
for i := len(ipv6) - bytesToZero; i < len(ipv6); i++ {
ipv6[i] = 0
}
// Note that this doesn't have the "/64" suffix customary with a CIDR representation,
// but those three bytes add nothing for us.
return ipv6.String()
}
-624
View File
@@ -1,624 +0,0 @@
// Package limiter provides data structure to configure rate-limiter.
package limiter
import (
"net/http"
"sync"
"time"
cache "github.com/go-pkgz/expirable-cache/v3"
"github.com/didip/tollbooth/v8/internal/time/rate"
)
// New is a constructor for Limiter.
func New(generalExpirableOptions *ExpirableOptions) *Limiter {
lmt := &Limiter{}
lmt.SetMessageContentType("text/plain; charset=utf-8").
SetMessage("You have reached maximum request limit.").
SetStatusCode(429).
SetOnLimitReached(nil).
SetForwardedForIndexFromBehind(0).
SetHeaders(make(map[string][]string)).
SetContextValues(make(map[string][]string)).
SetIgnoreURL(false)
if generalExpirableOptions != nil {
lmt.generalExpirableOptions = generalExpirableOptions
} else {
lmt.generalExpirableOptions = &ExpirableOptions{}
}
// Default for DefaultExpirationTTL is 10 years.
if lmt.generalExpirableOptions.DefaultExpirationTTL <= 0 {
lmt.generalExpirableOptions.DefaultExpirationTTL = 87600 * time.Hour
}
lmt.tokenBuckets = cache.NewCache[string, *rate.Limiter]().WithTTL(lmt.generalExpirableOptions.DefaultExpirationTTL)
lmt.basicAuthUsers = cache.NewCache[string, bool]().WithTTL(lmt.generalExpirableOptions.DefaultExpirationTTL)
return lmt
}
// IPLookup is a config struct to define how users want to pick the remote IP address.
type IPLookup struct {
// The name of lookup method.
// Possible options are: RemoteAddr, X-Forwarded-For, X-Real-IP, CF-Connecting-IP
// All other headers are considered unknown and will be ignored.
Name string
// The index position to pick the ip address from a comma separated list.
// The index goes from right to left.
IndexFromRight int
}
// Limiter is a config struct to limit a particular request handler.
type Limiter struct {
// Maximum number of requests to limit per second.
max float64
// Limiter burst size
burst int
// HTTP message when limit is reached.
message string
// Content-Type for Message
messageContentType string
// HTTP status code when limit is reached.
statusCode int
// A function to call when a request is rejected.
onLimitReached func(w http.ResponseWriter, r *http.Request)
// An option to write back what you want upon reaching a limit.
overrideDefaultResponseWriter bool
// Explicitly define how to look up IP address.
// This is intended to replace ipLookups
explicitIPLookup IPLookup
forwardedForIndex int
// List of HTTP Methods to limit (GET, POST, PUT, etc.).
// Empty means limit all methods.
methods []string
// Able to configure token bucket expirations.
generalExpirableOptions *ExpirableOptions
// List of basic auth usernames to limit.
basicAuthUsers cache.Cache[string, bool]
// Map of HTTP headers to limit.
// Empty means skip headers checking.
headers map[string]cache.Cache[string, bool]
// Map of Context values to limit.
contextValues map[string]cache.Cache[string, bool]
// Map of limiters with TTL
tokenBuckets cache.Cache[string, *rate.Limiter]
// Ignore URL on the rate limiter keys
ignoreURL bool
tokenBucketExpirationTTL time.Duration
basicAuthExpirationTTL time.Duration
headerEntryExpirationTTL time.Duration
contextEntryExpirationTTL time.Duration
sync.RWMutex
}
// SetTokenBucketExpirationTTL is thread-safe way of setting custom token bucket expiration TTL.
func (l *Limiter) SetTokenBucketExpirationTTL(ttl time.Duration) *Limiter {
l.Lock()
l.tokenBucketExpirationTTL = ttl
l.Unlock()
return l
}
// GetTokenBucketExpirationTTL is thread-safe way of getting custom token bucket expiration TTL.
func (l *Limiter) GetTokenBucketExpirationTTL() time.Duration {
l.RLock()
defer l.RUnlock()
return l.tokenBucketExpirationTTL
}
// SetBasicAuthExpirationTTL is thread-safe way of setting custom basic auth expiration TTL.
func (l *Limiter) SetBasicAuthExpirationTTL(ttl time.Duration) *Limiter {
l.Lock()
l.basicAuthExpirationTTL = ttl
l.Unlock()
return l
}
// GetBasicAuthExpirationTTL is thread-safe way of getting custom basic auth expiration TTL.
func (l *Limiter) GetBasicAuthExpirationTTL() time.Duration {
l.RLock()
defer l.RUnlock()
return l.basicAuthExpirationTTL
}
// SetHeaderEntryExpirationTTL is thread-safe way of setting custom basic auth expiration TTL.
func (l *Limiter) SetHeaderEntryExpirationTTL(ttl time.Duration) *Limiter {
l.Lock()
l.headerEntryExpirationTTL = ttl
l.Unlock()
return l
}
// GetHeaderEntryExpirationTTL is thread-safe way of getting custom basic auth expiration TTL.
func (l *Limiter) GetHeaderEntryExpirationTTL() time.Duration {
l.RLock()
defer l.RUnlock()
return l.headerEntryExpirationTTL
}
// SetContextValueEntryExpirationTTL is thread-safe way of setting custom Context value expiration TTL.
func (l *Limiter) SetContextValueEntryExpirationTTL(ttl time.Duration) *Limiter {
l.Lock()
l.contextEntryExpirationTTL = ttl
l.Unlock()
return l
}
// GetContextValueEntryExpirationTTL is thread-safe way of getting custom Context value expiration TTL.
func (l *Limiter) GetContextValueEntryExpirationTTL() time.Duration {
l.RLock()
defer l.RUnlock()
return l.contextEntryExpirationTTL
}
// SetMax is thread-safe way of setting maximum number of requests to limit per second.
func (l *Limiter) SetMax(max float64) *Limiter {
l.Lock()
l.max = max
l.Unlock()
return l
}
// GetMax is thread-safe way of getting maximum number of requests to limit per second.
func (l *Limiter) GetMax() float64 {
l.RLock()
defer l.RUnlock()
return l.max
}
// SetBurst is thread-safe way of setting maximum burst size.
func (l *Limiter) SetBurst(burst int) *Limiter {
l.Lock()
l.burst = burst
l.Unlock()
return l
}
// GetBurst is thread-safe way of setting maximum burst size.
func (l *Limiter) GetBurst() int {
l.RLock()
defer l.RUnlock()
return l.burst
}
// SetMessage is thread-safe way of setting HTTP message when limit is reached.
func (l *Limiter) SetMessage(msg string) *Limiter {
l.Lock()
l.message = msg
l.Unlock()
return l
}
// GetMessage is thread-safe way of getting HTTP message when limit is reached.
func (l *Limiter) GetMessage() string {
l.RLock()
defer l.RUnlock()
return l.message
}
// SetMessageContentType is thread-safe way of setting HTTP message Content-Type when limit is reached.
func (l *Limiter) SetMessageContentType(contentType string) *Limiter {
l.Lock()
l.messageContentType = contentType
l.Unlock()
return l
}
// GetMessageContentType is thread-safe way of getting HTTP message Content-Type when limit is reached.
func (l *Limiter) GetMessageContentType() string {
l.RLock()
defer l.RUnlock()
return l.messageContentType
}
// SetStatusCode is thread-safe way of setting HTTP status code when limit is reached.
func (l *Limiter) SetStatusCode(statusCode int) *Limiter {
l.Lock()
l.statusCode = statusCode
l.Unlock()
return l
}
// GetStatusCode is thread-safe way of getting HTTP status code when limit is reached.
func (l *Limiter) GetStatusCode() int {
l.RLock()
defer l.RUnlock()
return l.statusCode
}
// SetOnLimitReached is thread-safe way of setting after-rejection function when limit is reached.
func (l *Limiter) SetOnLimitReached(fn func(w http.ResponseWriter, r *http.Request)) *Limiter {
l.Lock()
l.onLimitReached = fn
l.Unlock()
return l
}
// ExecOnLimitReached is thread-safe way of executing after-rejection function when limit is reached.
func (l *Limiter) ExecOnLimitReached(w http.ResponseWriter, r *http.Request) {
l.RLock()
fn := l.onLimitReached
l.RUnlock()
if fn != nil {
fn(w, r)
}
}
// SetOverrideDefaultResponseWriter is a thread-safe way of setting the response writer override variable.
func (l *Limiter) SetOverrideDefaultResponseWriter(override bool) *Limiter {
l.Lock()
l.overrideDefaultResponseWriter = override
l.Unlock()
return l
}
// GetOverrideDefaultResponseWriter is a thread-safe way of getting the response writer override variable.
func (l *Limiter) GetOverrideDefaultResponseWriter() bool {
l.RLock()
defer l.RUnlock()
return l.overrideDefaultResponseWriter
}
// SetIPLookup is thread-safe way of setting an explicit way to look up IP address.
// This method is intended to replace SetIPLookups (version 6 or older).
func (l *Limiter) SetIPLookup(lookup IPLookup) *Limiter {
l.Lock()
l.explicitIPLookup = lookup
l.Unlock()
return l
}
// GetIPLookup is thread-safe way of getting an explicit way to look up IP address.
// This method is intended to replace the old GetIPLookups (version 6 or older).
func (l *Limiter) GetIPLookup() IPLookup {
l.RLock()
defer l.RUnlock()
return l.explicitIPLookup
}
// SetIgnoreURL is thread-safe way of setting whenever ignore the URL on rate limit keys
func (l *Limiter) SetIgnoreURL(enabled bool) *Limiter {
l.Lock()
l.ignoreURL = enabled
l.Unlock()
return l
}
// GetIgnoreURL returns whether the URL is ignored in the rate limit key set
func (l *Limiter) GetIgnoreURL() bool {
l.RLock()
defer l.RUnlock()
return l.ignoreURL
}
// SetForwardedForIndexFromBehind is thread-safe way of setting which X-Forwarded-For index to choose.
func (l *Limiter) SetForwardedForIndexFromBehind(forwardedForIndex int) *Limiter {
l.Lock()
l.forwardedForIndex = forwardedForIndex
l.Unlock()
return l
}
// GetForwardedForIndexFromBehind is thread-safe way of getting which X-Forwarded-For index to choose.
func (l *Limiter) GetForwardedForIndexFromBehind() int {
l.RLock()
defer l.RUnlock()
return l.forwardedForIndex
}
// SetMethods is thread-safe way of setting list of HTTP Methods to limit (GET, POST, PUT, etc.).
func (l *Limiter) SetMethods(methods []string) *Limiter {
l.Lock()
l.methods = methods
l.Unlock()
return l
}
// GetMethods is thread-safe way of getting list of HTTP Methods to limit (GET, POST, PUT, etc.).
func (l *Limiter) GetMethods() []string {
l.RLock()
defer l.RUnlock()
return l.methods
}
// SetBasicAuthUsers is thread-safe way of setting list of basic auth usernames to limit.
func (l *Limiter) SetBasicAuthUsers(basicAuthUsers []string) *Limiter {
ttl := l.GetBasicAuthExpirationTTL()
if ttl <= 0 {
ttl = l.generalExpirableOptions.DefaultExpirationTTL
}
for _, basicAuthUser := range basicAuthUsers {
l.basicAuthUsers.Set(basicAuthUser, true, ttl)
}
return l
}
// GetBasicAuthUsers is thread-safe way of getting list of basic auth usernames to limit.
func (l *Limiter) GetBasicAuthUsers() []string {
return l.basicAuthUsers.Keys()
}
// RemoveBasicAuthUsers is thread-safe way of removing basic auth usernames from existing list.
func (l *Limiter) RemoveBasicAuthUsers(basicAuthUsers []string) *Limiter {
for _, toBeRemoved := range basicAuthUsers {
l.basicAuthUsers.Invalidate(toBeRemoved)
}
return l
}
// DeleteExpiredTokenBuckets is thread-safe way of deleting expired token buckets
func (l *Limiter) DeleteExpiredTokenBuckets() {
l.tokenBuckets.DeleteExpired()
}
// SetHeaders is thread-safe way of setting map of HTTP headers to limit.
func (l *Limiter) SetHeaders(headers map[string][]string) *Limiter {
if l.headers == nil {
l.headers = make(map[string]cache.Cache[string, bool])
}
for header, entries := range headers {
l.SetHeader(header, entries)
}
return l
}
// GetHeaders is thread-safe way of getting map of HTTP headers to limit.
func (l *Limiter) GetHeaders() map[string][]string {
results := make(map[string][]string)
l.RLock()
defer l.RUnlock()
for header, entriesAsGoCache := range l.headers {
results[header] = entriesAsGoCache.Keys()
}
return results
}
// SetHeader is thread-safe way of setting entries of 1 HTTP header.
func (l *Limiter) SetHeader(header string, entries []string) *Limiter {
l.RLock()
existing, found := l.headers[header]
l.RUnlock()
ttl := l.GetHeaderEntryExpirationTTL()
if ttl <= 0 {
ttl = l.generalExpirableOptions.DefaultExpirationTTL
}
if !found {
existing = cache.NewCache[string, bool]().WithTTL(ttl)
}
for _, entry := range entries {
existing.Set(entry, true, ttl)
}
l.Lock()
l.headers[header] = existing
l.Unlock()
return l
}
// GetHeader is thread-safe way of getting entries of 1 HTTP header.
func (l *Limiter) GetHeader(header string) []string {
l.RLock()
entriesAsGoCache := l.headers[header]
l.RUnlock()
return entriesAsGoCache.Keys()
}
// RemoveHeader is thread-safe way of removing entries of 1 HTTP header.
func (l *Limiter) RemoveHeader(header string) *Limiter {
ttl := l.GetHeaderEntryExpirationTTL()
if ttl <= 0 {
ttl = l.generalExpirableOptions.DefaultExpirationTTL
}
l.Lock()
l.headers[header] = cache.NewCache[string, bool]().WithTTL(ttl)
l.Unlock()
return l
}
// RemoveHeaderEntries is thread-safe way of removing new entries to 1 HTTP header rule.
func (l *Limiter) RemoveHeaderEntries(header string, entriesForRemoval []string) *Limiter {
l.RLock()
entries, found := l.headers[header]
l.RUnlock()
if !found {
return l
}
for _, toBeRemoved := range entriesForRemoval {
entries.Invalidate(toBeRemoved)
}
return l
}
// SetContextValues is thread-safe way of setting map of HTTP headers to limit.
func (l *Limiter) SetContextValues(contextValues map[string][]string) *Limiter {
if l.contextValues == nil {
l.contextValues = make(map[string]cache.Cache[string, bool])
}
for contextValue, entries := range contextValues {
l.SetContextValue(contextValue, entries)
}
return l
}
// GetContextValues is thread-safe way of getting a map of Context values to limit.
func (l *Limiter) GetContextValues() map[string][]string {
results := make(map[string][]string)
l.RLock()
defer l.RUnlock()
for contextValue, entriesAsGoCache := range l.contextValues {
results[contextValue] = entriesAsGoCache.Keys()
}
return results
}
// SetContextValue is thread-safe way of setting entries of 1 Context value.
func (l *Limiter) SetContextValue(contextValue string, entries []string) *Limiter {
l.RLock()
existing, found := l.contextValues[contextValue]
l.RUnlock()
ttl := l.GetContextValueEntryExpirationTTL()
if ttl <= 0 {
ttl = l.generalExpirableOptions.DefaultExpirationTTL
}
if !found {
existing = cache.NewCache[string, bool]().WithTTL(ttl)
}
for _, entry := range entries {
existing.Set(entry, true, ttl)
}
l.Lock()
l.contextValues[contextValue] = existing
l.Unlock()
return l
}
// GetContextValue is thread-safe way of getting 1 Context value entry.
func (l *Limiter) GetContextValue(contextValue string) []string {
l.RLock()
entriesAsGoCache := l.contextValues[contextValue]
l.RUnlock()
return entriesAsGoCache.Keys()
}
// RemoveContextValue is thread-safe way of removing entries of 1 Context value.
func (l *Limiter) RemoveContextValue(contextValue string) *Limiter {
ttl := l.GetContextValueEntryExpirationTTL()
if ttl <= 0 {
ttl = l.generalExpirableOptions.DefaultExpirationTTL
}
l.Lock()
l.contextValues[contextValue] = cache.NewCache[string, bool]().WithTTL(ttl)
l.Unlock()
return l
}
// RemoveContextValuesEntries is thread-safe way of removing entries to a ContextValue.
func (l *Limiter) RemoveContextValuesEntries(contextValue string, entriesForRemoval []string) *Limiter {
l.RLock()
entries, found := l.contextValues[contextValue]
l.RUnlock()
if !found {
return l
}
for _, toBeRemoved := range entriesForRemoval {
entries.Invalidate(toBeRemoved)
}
return l
}
func (l *Limiter) limitReachedWithTokenBucketTTL(key string, tokenBucketTTL time.Duration) bool {
lmtMax := l.GetMax()
lmtBurst := l.GetBurst()
l.Lock()
defer l.Unlock()
if _, found := l.tokenBuckets.Get(key); !found {
l.tokenBuckets.Set(
key,
rate.NewLimiter(rate.Limit(lmtMax), lmtBurst),
tokenBucketTTL,
)
}
expiringMap, found := l.tokenBuckets.Get(key)
if !found {
return false
}
return !expiringMap.Allow()
}
// LimitReached returns a bool indicating if the Bucket identified by key ran out of tokens.
func (l *Limiter) LimitReached(key string) bool {
ttl := l.GetTokenBucketExpirationTTL()
if ttl <= 0 {
ttl = l.generalExpirableOptions.DefaultExpirationTTL
}
return l.limitReachedWithTokenBucketTTL(key, ttl)
}
// Tokens returns current amount of tokens left in the Bucket identified by key.
func (l *Limiter) Tokens(key string) int {
expiringMap, found := l.tokenBuckets.Get(key)
if !found {
return 0
}
return int(expiringMap.TokensAt(time.Now()))
}
@@ -1,14 +0,0 @@
package limiter
import (
"time"
)
// ExpirableOptions are options used for new limiter creation
type ExpirableOptions struct {
DefaultExpirationTTL time.Duration
// How frequently expire job triggers
// Deprecated: not used anymore
ExpireJobInterval time.Duration
}
-375
View File
@@ -1,375 +0,0 @@
// Package tollbooth provides rate-limiting logic to HTTP request handler.
package tollbooth
import (
"fmt"
"math"
"net/http"
"strings"
"github.com/didip/tollbooth/v8/errors"
"github.com/didip/tollbooth/v8/libstring"
"github.com/didip/tollbooth/v8/limiter"
)
// setResponseHeaders configures X-Rate-Limit-Limit and X-Rate-Limit-Duration
func setResponseHeaders(lmt *limiter.Limiter, w http.ResponseWriter, r *http.Request) {
w.Header().Add("X-Rate-Limit-Limit", fmt.Sprintf("%.2f", lmt.GetMax()))
w.Header().Add("X-Rate-Limit-Duration", "1")
xForwardedFor := r.Header.Get("X-Forwarded-For")
if strings.TrimSpace(xForwardedFor) != "" {
w.Header().Add("X-Rate-Limit-Request-Forwarded-For", xForwardedFor)
}
w.Header().Add("X-Rate-Limit-Request-Remote-Addr", r.RemoteAddr)
}
// setRateLimitResponseHeaders configures RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset
// as seen at https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers
func setRateLimitResponseHeaders(lmt *limiter.Limiter, w http.ResponseWriter, tokensLeft int) {
w.Header().Add("RateLimit-Limit", fmt.Sprintf("%d", int(math.Round(lmt.GetMax()))))
w.Header().Add("RateLimit-Reset", "1")
w.Header().Add("RateLimit-Remaining", fmt.Sprintf("%d", tokensLeft))
}
// NewLimiter is a convenience function to limiter.New.
func NewLimiter(max float64, tbOptions *limiter.ExpirableOptions) *limiter.Limiter {
return limiter.New(tbOptions).
SetMax(max).
SetBurst(int(math.Max(1, max)))
}
// LimitByKeys keeps track number of request made by keys separated by pipe.
// It returns HTTPError when limit is exceeded.
func LimitByKeys(lmt *limiter.Limiter, keys []string) *errors.HTTPError {
err, _ := LimitByKeysAndReturn(lmt, keys)
return err
}
// LimitByKeysAndReturn keeps track number of request made by keys separated by pipe.
// It returns HTTPError when limit is exceeded, and also returns the current limit value.
func LimitByKeysAndReturn(lmt *limiter.Limiter, keys []string) (*errors.HTTPError, int) {
if lmt.LimitReached(strings.Join(keys, "|")) {
return &errors.HTTPError{Message: lmt.GetMessage(), StatusCode: lmt.GetStatusCode()}, 0
}
return nil, lmt.Tokens(strings.Join(keys, "|"))
}
// ShouldSkipLimiter is a series of filter that decides if request should be limited or not.
func ShouldSkipLimiter(lmt *limiter.Limiter, r *http.Request) bool {
// ---------------------------------
// Filter by remote ip
// If we are unable to find remoteIP, skip limiter
remoteIP := libstring.RemoteIPFromIPLookup(lmt.GetIPLookup(), r)
remoteIP = libstring.CanonicalizeIP(remoteIP)
if remoteIP == "" {
return true
}
// ---------------------------------
// Filter by request method
lmtMethods := lmt.GetMethods()
lmtMethodsIsSet := len(lmtMethods) > 0
if lmtMethodsIsSet {
// If request does not contain all of the methods in limiter,
// skip limiter
requestMethodDefinedInLimiter := libstring.StringInSlice(lmtMethods, r.Method)
if !requestMethodDefinedInLimiter {
return true
}
}
// ---------------------------------
// Filter by request headers
lmtHeaders := lmt.GetHeaders()
lmtHeadersIsSet := len(lmtHeaders) > 0
if lmtHeadersIsSet {
// If request does not contain all of the headers in limiter,
// skip limiter
requestHeadersDefinedInLimiter := false
for headerKey := range lmtHeaders {
reqHeaderValue := r.Header.Get(headerKey)
if reqHeaderValue != "" {
requestHeadersDefinedInLimiter = true
break
}
}
if !requestHeadersDefinedInLimiter {
return true
}
// ------------------------------
// If request contains the header key but not the values,
// skip limiter
requestHeadersDefinedInLimiter = false
for headerKey, headerValues := range lmtHeaders {
if len(headerValues) == 0 {
requestHeadersDefinedInLimiter = true
continue
}
for _, headerValue := range headerValues {
if r.Header.Get(headerKey) == headerValue {
requestHeadersDefinedInLimiter = true
break
}
}
}
if !requestHeadersDefinedInLimiter {
return true
}
}
// ---------------------------------
// Filter by context values
lmtContextValues := lmt.GetContextValues()
lmtContextValuesIsSet := len(lmtContextValues) > 0
if lmtContextValuesIsSet {
// If request does not contain all of the contexts in limiter,
// skip limiter
requestContextValuesDefinedInLimiter := false
for contextKey := range lmtContextValues {
reqContextValue := fmt.Sprintf("%v", r.Context().Value(contextKey))
if reqContextValue != "" {
requestContextValuesDefinedInLimiter = true
break
}
}
if !requestContextValuesDefinedInLimiter {
return true
}
// ------------------------------
// If request contains the context key but not the values,
// skip limiter
requestContextValuesDefinedInLimiter = false
for contextKey, contextValues := range lmtContextValues {
for _, contextValue := range contextValues {
if r.Header.Get(contextKey) == contextValue {
requestContextValuesDefinedInLimiter = true
break
}
}
}
if !requestContextValuesDefinedInLimiter {
return true
}
}
// ---------------------------------
// Filter by basic auth usernames
lmtBasicAuthUsers := lmt.GetBasicAuthUsers()
lmtBasicAuthUsersIsSet := len(lmtBasicAuthUsers) > 0
if lmtBasicAuthUsersIsSet {
// If request does not contain all of the basic auth users in limiter,
// skip limiter
requestAuthUsernameDefinedInLimiter := false
username, _, ok := r.BasicAuth()
if ok && libstring.StringInSlice(lmtBasicAuthUsers, username) {
requestAuthUsernameDefinedInLimiter = true
}
if !requestAuthUsernameDefinedInLimiter {
return true
}
}
return false
}
// BuildKeys generates a slice of keys to rate-limit by given limiter and request structs.
func BuildKeys(lmt *limiter.Limiter, r *http.Request) [][]string {
remoteIP := libstring.RemoteIPFromIPLookup(lmt.GetIPLookup(), r)
remoteIP = libstring.CanonicalizeIP(remoteIP)
path := r.URL.Path
sliceKeys := make([][]string, 0)
lmtMethods := lmt.GetMethods()
lmtHeaders := lmt.GetHeaders()
lmtContextValues := lmt.GetContextValues()
lmtBasicAuthUsers := lmt.GetBasicAuthUsers()
lmtIgnoreURL := lmt.GetIgnoreURL()
lmtHeadersIsSet := len(lmtHeaders) > 0
lmtContextValuesIsSet := len(lmtContextValues) > 0
lmtBasicAuthUsersIsSet := len(lmtBasicAuthUsers) > 0
usernameToLimit := ""
if lmtBasicAuthUsersIsSet {
username, _, ok := r.BasicAuth()
if ok && libstring.StringInSlice(lmtBasicAuthUsers, username) {
usernameToLimit = username
}
}
headerValuesToLimit := [][]string{}
if lmtHeadersIsSet {
for headerKey, headerValues := range lmtHeaders {
reqHeaderValue := r.Header.Get(headerKey)
if reqHeaderValue == "" {
continue
}
if len(headerValues) == 0 {
// If header values are empty, rate-limit all request containing headerKey.
headerValuesToLimit = append(headerValuesToLimit, []string{headerKey, reqHeaderValue})
} else {
// If header values are not empty, rate-limit all request with headerKey and headerValues.
for _, headerValue := range headerValues {
if r.Header.Get(headerKey) == headerValue {
headerValuesToLimit = append(headerValuesToLimit, []string{headerKey, headerValue})
break
}
}
}
}
}
contextValuesToLimit := [][]string{}
if lmtContextValuesIsSet {
for contextKey, contextValues := range lmtContextValues {
reqContextValue := fmt.Sprintf("%v", r.Context().Value(contextKey))
if reqContextValue == "" {
continue
}
if len(contextValues) == 0 {
// If context values are empty, rate-limit all request containing contextKey.
contextValuesToLimit = append(contextValuesToLimit, []string{contextKey, reqContextValue})
} else {
// If context values are not empty, rate-limit all request with contextKey and contextValues.
for _, contextValue := range contextValues {
if reqContextValue == contextValue {
contextValuesToLimit = append(contextValuesToLimit, []string{contextKey, contextValue})
break
}
}
}
}
}
sliceKey := []string{remoteIP}
if !lmtIgnoreURL {
sliceKey = append(sliceKey, path)
}
sliceKey = append(sliceKey, lmtMethods...)
for _, header := range headerValuesToLimit {
sliceKey = append(sliceKey, header[0], header[1])
}
for _, contextValue := range contextValuesToLimit {
sliceKey = append(sliceKey, contextValue[0], contextValue[1])
}
sliceKey = append(sliceKey, usernameToLimit)
sliceKeys = append(sliceKeys, sliceKey)
return sliceKeys
}
// LimitByRequest builds keys based on http.Request struct,
// loops through all the keys, and check if any one of them returns HTTPError.
func LimitByRequest(lmt *limiter.Limiter, w http.ResponseWriter, r *http.Request) *errors.HTTPError {
setResponseHeaders(lmt, w, r)
shouldSkip := ShouldSkipLimiter(lmt, r)
if shouldSkip {
return nil
}
sliceKeys := BuildKeys(lmt, r)
// Get the lowest value over all keys to return in headers.
// Start with high arbitrary number so that any limit returned would be lower and would
// overwrite the value we start with.
var tokensLeft = math.MaxInt32
// Loop sliceKeys and check if one of them has error.
for _, keys := range sliceKeys {
httpError, keysLimit := LimitByKeysAndReturn(lmt, keys)
if tokensLeft > keysLimit {
tokensLeft = keysLimit
}
if httpError != nil {
setRateLimitResponseHeaders(lmt, w, tokensLeft)
return httpError
}
}
setRateLimitResponseHeaders(lmt, w, tokensLeft)
return nil
}
// LimitHandler is a middleware that performs rate-limiting given http.Handler struct.
func LimitHandler(lmt *limiter.Limiter, next http.Handler) http.Handler {
middle := func(w http.ResponseWriter, r *http.Request) {
httpError := LimitByRequest(lmt, w, r)
if httpError != nil {
lmt.ExecOnLimitReached(w, r)
if lmt.GetOverrideDefaultResponseWriter() {
return
}
w.Header().Add("Content-Type", lmt.GetMessageContentType())
w.WriteHeader(httpError.StatusCode)
w.Write([]byte(httpError.Message))
return
}
// There's no rate-limit error, serve the next handler.
next.ServeHTTP(w, r)
}
return http.HandlerFunc(middle)
}
// LimitFuncHandler is a middleware that performs rate-limiting given request handler function.
func LimitFuncHandler(lmt *limiter.Limiter, nextFunc func(http.ResponseWriter, *http.Request)) http.Handler {
return LimitHandler(lmt, http.HandlerFunc(nextFunc))
}
// HTTPMiddleware wraps http.Handler with tollbooth limiter
func HTTPMiddleware(lmt *limiter.Limiter) func(http.Handler) http.Handler {
// // set IP lookup only if not set
if lmt.GetIPLookup().Name == "" {
lmt.SetIPLookup(limiter.IPLookup{Name: "RemoteAddr"})
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
select {
case <-r.Context().Done():
http.Error(w, "Context was canceled", http.StatusServiceUnavailable)
return
default:
if httpError := LimitByRequest(lmt, w, r); httpError != nil {
lmt.ExecOnLimitReached(w, r)
w.Header().Add("Content-Type", lmt.GetMessageContentType())
w.WriteHeader(httpError.StatusCode)
w.Write([]byte(httpError.Message)) //nolint:gosec // not much we can do here with failed write
return
}
next.ServeHTTP(w, r)
}
})
}
}
+12
View File
@@ -50,8 +50,20 @@ func makeDeadline(d time.Duration) fasttime {
// Start or extend clock if necessary.
if end > fast.clockEnd.read() {
// If time.Since(last use) > timeout, there's a chance that
// fast.current will no longer be updated, which can lead to
// incorrect 'end' calculations that can trigger a false timeout
fast.mu.Lock()
if !fast.running && !fast.start.IsZero() {
// update fast.current
fast.current.write(durationToTicks(time.Since(fast.start)))
// recalculate our end value
end = fast.current.read() + durationToTicks(d+clockPeriod)
}
fast.mu.Unlock()
extendClock(end)
}
return end
}
+4 -2
View File
@@ -20,7 +20,9 @@ and [docgen](https://github.com/go-chi/docgen). We hope you enjoy it too!
## Install
`go get -u github.com/go-chi/chi/v5`
```sh
go get -u github.com/go-chi/chi/v5
```
## Features
@@ -194,7 +196,7 @@ type Router interface {
// path, with a fresh middleware stack for the inline-Router.
Group(fn func(r Router)) Router
// Route mounts a sub-Router along a `pattern`` string.
// Route mounts a sub-Router along a `pattern` string.
Route(pattern string, fn func(r Router)) Router
// Mount attaches another http.Handler along ./pattern/*
+1 -2
View File
@@ -37,8 +37,7 @@
//
// A placeholder with a name followed by a colon allows a regular
// expression match, for example {number:\\d+}. The regular expression
// syntax is Go's normal regexp RE2 syntax, except that regular expressions
// including { or } are not supported, and / will never be
// syntax is Go's normal regexp RE2 syntax, except that / will never be
// matched. An anonymous regexp pattern is allowed, using an empty string
// before the colon in the placeholder, such as {:\\d+}
//
+5 -4
View File
@@ -133,11 +133,12 @@ func (x *Context) RoutePattern() string {
return routePattern
}
// replaceWildcards takes a route pattern and recursively replaces all
// occurrences of "/*/" to "/".
// replaceWildcards takes a route pattern and replaces all occurrences of
// "/*/" with "/". It iteratively runs until no wildcards remain to
// correctly handle consecutive wildcards.
func replaceWildcards(p string) string {
if strings.Contains(p, "/*/") {
return replaceWildcards(strings.Replace(p, "/*/", "/", -1))
for strings.Contains(p, "/*/") {
p = strings.ReplaceAll(p, "/*/", "/")
}
return p
}
+9 -15
View File
@@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"strings"
@@ -160,16 +159,14 @@ func (c *Compressor) SetEncoder(encoding string, fn EncoderFunc) {
delete(c.encoders, encoding)
// If the encoder supports Resetting (IoReseterWriter), then it can be pooled.
encoder := fn(ioutil.Discard, c.level)
if encoder != nil {
if _, ok := encoder.(ioResetterWriter); ok {
pool := &sync.Pool{
New: func() interface{} {
return fn(ioutil.Discard, c.level)
},
}
c.pooledEncoders[encoding] = pool
encoder := fn(io.Discard, c.level)
if _, ok := encoder.(ioResetterWriter); ok {
pool := &sync.Pool{
New: func() interface{} {
return fn(io.Discard, c.level)
},
}
c.pooledEncoders[encoding] = pool
}
// If the encoder is not in the pooledEncoders, add it to the normal encoders.
if _, ok := c.pooledEncoders[encoding]; !ok {
@@ -277,16 +274,13 @@ type compressResponseWriter struct {
func (cw *compressResponseWriter) isCompressible() bool {
// Parse the first part of the Content-Type response header.
contentType := cw.Header().Get("Content-Type")
if idx := strings.Index(contentType, ";"); idx >= 0 {
contentType = contentType[0:idx]
}
contentType, _, _ = strings.Cut(contentType, ";")
// Is the content type compressible?
if _, ok := cw.contentTypes[contentType]; ok {
return true
}
if idx := strings.Index(contentType, "/"); idx > 0 {
contentType = contentType[0:idx]
if contentType, _, hadSlash := strings.Cut(contentType, "/"); hadSlash {
_, ok := cw.contentWildcards[contentType]
return ok
}
+4 -5
View File
@@ -40,11 +40,10 @@ func contentEncoding(ce string, charsets ...string) bool {
// Split a string in two parts, cleaning any whitespace.
func split(str, sep string) (string, string) {
var a, b string
var parts = strings.SplitN(str, sep, 2)
a = strings.TrimSpace(parts[0])
if len(parts) == 2 {
b = strings.TrimSpace(parts[1])
a, b, found := strings.Cut(str, sep)
a = strings.TrimSpace(a)
if found {
b = strings.TrimSpace(b)
}
return a, b
+2 -2
View File
@@ -31,7 +31,8 @@ func AllowContentType(contentTypes ...string) func(http.Handler) http.Handler {
return
}
s := strings.ToLower(strings.TrimSpace(strings.Split(r.Header.Get("Content-Type"), ";")[0]))
s, _, _ := strings.Cut(r.Header.Get("Content-Type"), ";")
s = strings.ToLower(strings.TrimSpace(s))
if _, ok := allowedContentTypes[s]; ok {
next.ServeHTTP(w, r)
@@ -42,4 +43,3 @@ func AllowContentType(contentTypes ...string) func(http.Handler) http.Handler {
})
}
}
+3
View File
@@ -1,3 +1,6 @@
//go:build !tinygo
// +build !tinygo
package middleware
import (
+1 -5
View File
@@ -47,11 +47,7 @@ func realIP(r *http.Request) string {
} else if xrip := r.Header.Get(xRealIP); xrip != "" {
ip = xrip
} else if xff := r.Header.Get(xForwardedFor); xff != "" {
i := strings.Index(xff, ",")
if i == -1 {
i = len(xff)
}
ip = xff[:i]
ip, _, _ = strings.Cut(xff, ",")
}
if ip == "" || net.ParseIP(ip) == nil {
return ""
+1 -7
View File
@@ -133,13 +133,7 @@ type Pattern struct {
func NewPattern(value string) Pattern {
p := Pattern{}
if i := strings.IndexByte(value, '*'); i >= 0 {
p.wildcard = true
p.prefix = value[0:i]
p.suffix = value[i+1:]
} else {
p.prefix = value
}
p.prefix, p.suffix, p.wildcard = strings.Cut(value, "*")
return p
}

Some files were not shown because too many files have changed in this diff Show More