├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── assets ├── create.bash ├── syntaxes.bin └── themes.bin ├── ci └── github-actions │ ├── macos-install-packages │ └── ubuntu-install-packages ├── refmt-serde ├── .cargo │ └── config.toml ├── Cargo.lock ├── Cargo.toml └── src │ ├── lib.rs │ └── serde │ ├── json.rs │ ├── mod.rs │ ├── toml.rs │ └── yaml.rs └── src ├── assets.rs ├── bin ├── generate_assets │ └── main.rs └── refmt │ ├── app.rs │ ├── main.rs │ └── printer.rs ├── errors.rs ├── format.rs └── lib.rs /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "20:00" 8 | open-pull-requests-limit: 10 9 | ignore: 10 | - dependency-name: anyhow 11 | versions: 12 | - 1.0.39 13 | - dependency-name: env_logger 14 | versions: 15 | - 0.8.3 16 | - dependency-name: serde_yaml 17 | versions: 18 | - 0.8.16 19 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | test: 9 | name: test 10 | env: 11 | # Emit backtraces on panics. 12 | RUST_BACKTRACE: 1 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | build: 17 | - stable 18 | - macos 19 | - win-msvc 20 | - win-gnu 21 | include: 22 | - build: stable 23 | os: ubuntu-18.04 24 | rust: stable 25 | - build: macos 26 | os: macos-latest 27 | rust: stable 28 | - build: win-msvc 29 | os: windows-2019 30 | rust: stable 31 | - build: win-gnu 32 | os: windows-2019 33 | rust: stable-x86_64-gnu 34 | 35 | steps: 36 | - name: Checkout repository 37 | uses: actions/checkout@v2 38 | 39 | - name: Install packages (Ubuntu) 40 | if: matrix.os == 'ubuntu-18.04' 41 | run: | 42 | ci/github-actions/ubuntu-install-packages 43 | 44 | - name: Install packages (macOS) 45 | if: matrix.os == 'macos-latest' 46 | run: | 47 | ci/github-actions/macos-install-packages 48 | 49 | - name: Install Rust 50 | uses: actions-rs/toolchain@v1 51 | with: 52 | toolchain: ${{ matrix.rust }} 53 | profile: minimal 54 | override: true 55 | 56 | - name: Build 57 | run: | 58 | cargo build --verbose 59 | cargo test --verbose --all 60 | 61 | rustfmt: 62 | name: rustfmt 63 | runs-on: ubuntu-18.04 64 | steps: 65 | - name: Checkout repository 66 | uses: actions/checkout@v2 67 | 68 | - name: Install Rust 69 | uses: actions-rs/toolchain@v1 70 | with: 71 | toolchain: stable 72 | override: true 73 | profile: minimal 74 | components: rustfmt 75 | 76 | - name: Check formatting 77 | run: | 78 | cargo fmt --all -- --check 79 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '[0-9]+.[0-9]+.[0-9]+*' 7 | 8 | env: 9 | APP_NAME: refmt 10 | 11 | jobs: 12 | create-release: 13 | name: create-release 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Create artifacts directory 17 | run: mkdir artifacts 18 | 19 | - name: Get the release version from the tag 20 | if: env.APP_VERSION == '' 21 | run: | 22 | echo "APP_VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV 23 | 24 | - name: Confirm the app version 25 | run: | 26 | echo "Version is: ${{ env.APP_VERSION }}" 27 | 28 | - name: Create GitHub release 29 | id: release 30 | uses: actions/create-release@v1 31 | env: 32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | with: 34 | tag_name: ${{ env.APP_VERSION }} 35 | release_name: ${{ env.APP_VERSION }} 36 | 37 | - name: Save release upload URL to artifact 38 | run: echo "${{ steps.release.outputs.upload_url }}" > artifacts/release-upload-url 39 | 40 | - name: Save version number to artifact 41 | run: echo "${{ env.APP_VERSION }}" > artifacts/release-version 42 | 43 | - name: Upload artifacts 44 | uses: actions/upload-artifact@v1 45 | with: 46 | name: artifacts 47 | path: artifacts 48 | 49 | build-release: 50 | name: build / ${{ matrix.target }} 51 | needs: ['create-release'] 52 | runs-on: ${{ matrix.os }} 53 | strategy: 54 | matrix: 55 | build: [linux, macos, win-msvc, win-gnu] 56 | include: 57 | - build: linux 58 | os: ubuntu-18.04 59 | rust: stable 60 | target: x86_64-unknown-linux-musl 61 | - build: macos 62 | os: macos-latest 63 | rust: stable 64 | target: x86_64-apple-darwin 65 | - build: win-msvc 66 | os: windows-2019 67 | rust: nightly 68 | target: x86_64-pc-windows-msvc 69 | - build: win-gnu 70 | os: windows-2019 71 | rust: nightly-x86_64-gnu 72 | target: x86_64-pc-windows-gnu 73 | 74 | steps: 75 | - name: Checkout 76 | uses: actions/checkout@v2 77 | with: 78 | fetch-depth: 1 79 | 80 | - name: Install packages (Ubuntu) 81 | if: matrix.os == 'ubuntu-18.04' 82 | run: | 83 | ci/github-actions/ubuntu-install-packages 84 | 85 | - name: Install packages (macOS) 86 | if: matrix.os == 'macos-latest' 87 | run: | 88 | ci/github-actions/macos-install-packages 89 | 90 | - name: Install Rust 91 | uses: actions-rs/toolchain@v1 92 | with: 93 | toolchain: ${{ matrix.rust }} 94 | profile: minimal 95 | override: true 96 | target: ${{ matrix.target }} 97 | 98 | - name: Get release download URL 99 | uses: actions/download-artifact@v1 100 | with: 101 | name: artifacts 102 | path: artifacts 103 | 104 | - name: Set release upload URL and release version 105 | shell: bash 106 | run: | 107 | release_upload_url="$(cat artifacts/release-upload-url)" 108 | RELEASE_UPLOAD_URL="$release_upload_url" 109 | echo "RELEASE_UPLOAD_URL=$release_upload_url" >> $GITHUB_ENV 110 | echo "release upload url: $RELEASE_UPLOAD_URL" 111 | 112 | release_version="$(cat artifacts/release-version)" 113 | RELEASE_VERSION="$release_version" 114 | echo "RELEASE_VERSION=$release_version" >> $GITHUB_ENV 115 | echo "release version: $RELEASE_VERSION" 116 | 117 | - name: Build release binary 118 | run: cargo build --verbose --release --target ${{ matrix.target }} 119 | 120 | - name: Strip release binary (linux and macos) 121 | if: matrix.build == 'linux' || matrix.build == 'macos' 122 | run: strip "target/${{ matrix.target }}/release/${{ env.APP_NAME }}" 123 | 124 | - name: Strip release binary (arm) 125 | if: matrix.build == 'linux-arm' 126 | run: | 127 | docker run --rm -v \ 128 | "$PWD/target:/target:Z" \ 129 | rustembedded/cross:arm-unknown-linux-gnueabihf \ 130 | arm-linux-gnueabihf-strip \ 131 | /target/arm-unknown-linux-gnueabihf/release/${{ env.APP_NAME }} 132 | 133 | - name: Build archive 134 | shell: bash 135 | run: | 136 | # NOTE: Consider adding script files to do below operations. 137 | staging="${{ env.APP_NAME }}-${{ env.RELEASE_VERSION }}-${{ matrix.target }}" 138 | mkdir -p "$staging" 139 | 140 | cp README.md LICENSE "$staging/" 141 | 142 | if [ "${{ matrix.os }}" = "windows-2019" ]; then 143 | cp "target/${{ matrix.target }}/release/${{ env.APP_NAME }}.exe" "$staging/" 144 | 7z a "$staging.zip" "$staging" 145 | echo "ASSET=$staging.zip" >> $GITHUB_ENV 146 | else 147 | cp "target/${{ matrix.target }}/release/${{ env.APP_NAME }}" "$staging/" 148 | tar czf "$staging.tar.gz" "$staging" 149 | echo "ASSET=$staging.tar.gz" >> $GITHUB_ENV 150 | fi 151 | 152 | - name: Upload release archive 153 | uses: actions/upload-release-asset@v1.0.1 154 | env: 155 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 156 | with: 157 | upload_url: ${{ env.RELEASE_UPLOAD_URL }} 158 | asset_path: ${{ env.ASSET }} 159 | asset_name: ${{ env.ASSET }} 160 | asset_content_type: application/octet-stream 161 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .fleet/ 3 | 4 | target/ 5 | **/*.rs.bk 6 | 7 | .envrc 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "assets/syntaxes/sublime_toml_highlighting"] 2 | path = assets/syntaxes/sublime_toml_highlighting 3 | url = https://github.com/jasonwilliams/sublime_toml_highlighting.git 4 | [submodule "assets/themes/sublime-monokai-extended"] 5 | path = assets/themes/sublime-monokai-extended 6 | url = https://github.com/jonschlinkert/sublime-monokai-extended 7 | [submodule "assets/syntaxes/Packages"] 8 | path = assets/syntaxes/Packages 9 | url = https://github.com/sublimehq/Packages.git 10 | [submodule "assets/themes/MonokaiJsonPlus"] 11 | path = assets/themes/MonokaiJsonPlus 12 | url = https://github.com/ColibriApps/MonokaiJsonPlus 13 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "adler32" 7 | version = "1.1.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "567b077b825e468cc974f0020d4082ee6e03132512f207ef1a02fd5d00d1f32d" 10 | 11 | [[package]] 12 | name = "aho-corasick" 13 | version = "0.7.13" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" 16 | dependencies = [ 17 | "memchr", 18 | ] 19 | 20 | [[package]] 21 | name = "ansi_term" 22 | version = "0.11.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 25 | dependencies = [ 26 | "winapi", 27 | ] 28 | 29 | [[package]] 30 | name = "ansi_term" 31 | version = "0.12.1" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 34 | dependencies = [ 35 | "winapi", 36 | ] 37 | 38 | [[package]] 39 | name = "anyhow" 40 | version = "1.0.40" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" 43 | 44 | [[package]] 45 | name = "atty" 46 | version = "0.2.14" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 49 | dependencies = [ 50 | "hermit-abi 0.1.14", 51 | "libc", 52 | "winapi", 53 | ] 54 | 55 | [[package]] 56 | name = "autocfg" 57 | version = "1.0.0" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 60 | 61 | [[package]] 62 | name = "base64" 63 | version = "0.12.2" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "e223af0dc48c96d4f8342ec01a4974f139df863896b316681efd36742f22cc67" 66 | 67 | [[package]] 68 | name = "bincode" 69 | version = "1.3.1" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" 72 | dependencies = [ 73 | "byteorder", 74 | "serde", 75 | ] 76 | 77 | [[package]] 78 | name = "bitflags" 79 | version = "1.2.1" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 82 | 83 | [[package]] 84 | name = "byteorder" 85 | version = "1.3.4" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 88 | 89 | [[package]] 90 | name = "cc" 91 | version = "1.0.54" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" 94 | 95 | [[package]] 96 | name = "cfg-if" 97 | version = "0.1.10" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 100 | 101 | [[package]] 102 | name = "cfg-if" 103 | version = "1.0.0" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 106 | 107 | [[package]] 108 | name = "chrono" 109 | version = "0.4.11" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" 112 | dependencies = [ 113 | "num-integer", 114 | "num-traits", 115 | ] 116 | 117 | [[package]] 118 | name = "clap" 119 | version = "2.33.1" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" 122 | dependencies = [ 123 | "ansi_term 0.11.0", 124 | "atty", 125 | "bitflags", 126 | "strsim", 127 | "term_size", 128 | "textwrap", 129 | "unicode-width", 130 | "vec_map", 131 | ] 132 | 133 | [[package]] 134 | name = "crc32fast" 135 | version = "1.2.0" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" 138 | dependencies = [ 139 | "cfg-if 0.1.10", 140 | ] 141 | 142 | [[package]] 143 | name = "env_logger" 144 | version = "0.10.0" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" 147 | dependencies = [ 148 | "humantime", 149 | "is-terminal", 150 | "log", 151 | "regex", 152 | "termcolor", 153 | ] 154 | 155 | [[package]] 156 | name = "errno" 157 | version = "0.2.8" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" 160 | dependencies = [ 161 | "errno-dragonfly", 162 | "libc", 163 | "winapi", 164 | ] 165 | 166 | [[package]] 167 | name = "errno-dragonfly" 168 | version = "0.1.2" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 171 | dependencies = [ 172 | "cc", 173 | "libc", 174 | ] 175 | 176 | [[package]] 177 | name = "flate2" 178 | version = "1.0.14" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "2cfff41391129e0a856d6d822600b8d71179d46879e310417eb9c762eb178b42" 181 | dependencies = [ 182 | "cfg-if 0.1.10", 183 | "crc32fast", 184 | "libc", 185 | "miniz_oxide", 186 | ] 187 | 188 | [[package]] 189 | name = "fnv" 190 | version = "1.0.7" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 193 | 194 | [[package]] 195 | name = "hashbrown" 196 | version = "0.12.3" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 199 | 200 | [[package]] 201 | name = "heck" 202 | version = "0.4.0" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 205 | 206 | [[package]] 207 | name = "hermit-abi" 208 | version = "0.1.14" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" 211 | dependencies = [ 212 | "libc", 213 | ] 214 | 215 | [[package]] 216 | name = "hermit-abi" 217 | version = "0.2.6" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" 220 | dependencies = [ 221 | "libc", 222 | ] 223 | 224 | [[package]] 225 | name = "humantime" 226 | version = "2.0.1" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "3c1ad908cc71012b7bea4d0c53ba96a8cba9962f048fa68d143376143d863b7a" 229 | 230 | [[package]] 231 | name = "indexmap" 232 | version = "1.9.2" 233 | source = "registry+https://github.com/rust-lang/crates.io-index" 234 | checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" 235 | dependencies = [ 236 | "autocfg", 237 | "hashbrown", 238 | ] 239 | 240 | [[package]] 241 | name = "io-lifetimes" 242 | version = "1.0.3" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" 245 | dependencies = [ 246 | "libc", 247 | "windows-sys", 248 | ] 249 | 250 | [[package]] 251 | name = "is-terminal" 252 | version = "0.4.2" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" 255 | dependencies = [ 256 | "hermit-abi 0.2.6", 257 | "io-lifetimes", 258 | "rustix", 259 | "windows-sys", 260 | ] 261 | 262 | [[package]] 263 | name = "itoa" 264 | version = "1.0.1" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" 267 | 268 | [[package]] 269 | name = "lazy_static" 270 | version = "1.4.0" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 273 | 274 | [[package]] 275 | name = "libc" 276 | version = "0.2.139" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" 279 | 280 | [[package]] 281 | name = "line-wrap" 282 | version = "0.1.1" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "f30344350a2a51da54c1d53be93fade8a237e545dbcc4bdbe635413f2117cab9" 285 | dependencies = [ 286 | "safemem", 287 | ] 288 | 289 | [[package]] 290 | name = "linked-hash-map" 291 | version = "0.5.3" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" 294 | 295 | [[package]] 296 | name = "linux-raw-sys" 297 | version = "0.1.4" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" 300 | 301 | [[package]] 302 | name = "log" 303 | version = "0.4.17" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 306 | dependencies = [ 307 | "cfg-if 1.0.0", 308 | ] 309 | 310 | [[package]] 311 | name = "memchr" 312 | version = "2.3.3" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" 315 | 316 | [[package]] 317 | name = "miniz_oxide" 318 | version = "0.3.7" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" 321 | dependencies = [ 322 | "adler32", 323 | ] 324 | 325 | [[package]] 326 | name = "num-integer" 327 | version = "0.1.43" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" 330 | dependencies = [ 331 | "autocfg", 332 | "num-traits", 333 | ] 334 | 335 | [[package]] 336 | name = "num-traits" 337 | version = "0.2.12" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" 340 | dependencies = [ 341 | "autocfg", 342 | ] 343 | 344 | [[package]] 345 | name = "once_cell" 346 | version = "1.17.0" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" 349 | 350 | [[package]] 351 | name = "onig" 352 | version = "6.0.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "bd91ccd8a02fce2f7e8a86655aec67bc6c171e6f8e704118a0e8c4b866a05a8a" 355 | dependencies = [ 356 | "bitflags", 357 | "lazy_static", 358 | "libc", 359 | "onig_sys", 360 | ] 361 | 362 | [[package]] 363 | name = "onig_sys" 364 | version = "69.5.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "3814583fad89f3c60ae0701d80e87e1fd3028741723deda72d0d4a0ecf0cb0db" 367 | dependencies = [ 368 | "cc", 369 | "pkg-config", 370 | ] 371 | 372 | [[package]] 373 | name = "pkg-config" 374 | version = "0.3.17" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" 377 | 378 | [[package]] 379 | name = "plist" 380 | version = "1.0.0" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "7b336d94e8e4ce29bf15bba393164629764744c567e8ad306cc1fdd0119967fd" 383 | dependencies = [ 384 | "base64", 385 | "chrono", 386 | "indexmap", 387 | "line-wrap", 388 | "serde", 389 | "xml-rs", 390 | ] 391 | 392 | [[package]] 393 | name = "proc-macro2" 394 | version = "1.0.49" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" 397 | dependencies = [ 398 | "unicode-ident", 399 | ] 400 | 401 | [[package]] 402 | name = "quote" 403 | version = "1.0.7" 404 | source = "registry+https://github.com/rust-lang/crates.io-index" 405 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" 406 | dependencies = [ 407 | "proc-macro2", 408 | ] 409 | 410 | [[package]] 411 | name = "refmt" 412 | version = "0.2.2" 413 | dependencies = [ 414 | "ansi_term 0.12.1", 415 | "anyhow", 416 | "atty", 417 | "clap", 418 | "env_logger", 419 | "log", 420 | "refmt-serde", 421 | "strum", 422 | "strum_macros", 423 | "syntect", 424 | "thiserror", 425 | ] 426 | 427 | [[package]] 428 | name = "refmt-serde" 429 | version = "0.3.0" 430 | dependencies = [ 431 | "once_cell", 432 | "serde", 433 | "serde_json", 434 | "serde_yaml", 435 | "thiserror", 436 | "toml", 437 | ] 438 | 439 | [[package]] 440 | name = "regex" 441 | version = "1.3.9" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" 444 | dependencies = [ 445 | "aho-corasick", 446 | "memchr", 447 | "regex-syntax", 448 | "thread_local", 449 | ] 450 | 451 | [[package]] 452 | name = "regex-syntax" 453 | version = "0.6.18" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" 456 | 457 | [[package]] 458 | name = "rustix" 459 | version = "0.36.6" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" 462 | dependencies = [ 463 | "bitflags", 464 | "errno", 465 | "io-lifetimes", 466 | "libc", 467 | "linux-raw-sys", 468 | "windows-sys", 469 | ] 470 | 471 | [[package]] 472 | name = "rustversion" 473 | version = "1.0.5" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" 476 | 477 | [[package]] 478 | name = "ryu" 479 | version = "1.0.5" 480 | source = "registry+https://github.com/rust-lang/crates.io-index" 481 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 482 | 483 | [[package]] 484 | name = "safemem" 485 | version = "0.3.3" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" 488 | 489 | [[package]] 490 | name = "same-file" 491 | version = "1.0.6" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 494 | dependencies = [ 495 | "winapi-util", 496 | ] 497 | 498 | [[package]] 499 | name = "serde" 500 | version = "1.0.152" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" 503 | dependencies = [ 504 | "serde_derive", 505 | ] 506 | 507 | [[package]] 508 | name = "serde_derive" 509 | version = "1.0.152" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" 512 | dependencies = [ 513 | "proc-macro2", 514 | "quote", 515 | "syn", 516 | ] 517 | 518 | [[package]] 519 | name = "serde_json" 520 | version = "1.0.91" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" 523 | dependencies = [ 524 | "indexmap", 525 | "itoa", 526 | "ryu", 527 | "serde", 528 | ] 529 | 530 | [[package]] 531 | name = "serde_yaml" 532 | version = "0.9.16" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "92b5b431e8907b50339b51223b97d102db8d987ced36f6e4d03621db9316c834" 535 | dependencies = [ 536 | "indexmap", 537 | "itoa", 538 | "ryu", 539 | "serde", 540 | "unsafe-libyaml", 541 | ] 542 | 543 | [[package]] 544 | name = "strsim" 545 | version = "0.8.0" 546 | source = "registry+https://github.com/rust-lang/crates.io-index" 547 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 548 | 549 | [[package]] 550 | name = "strum" 551 | version = "0.24.1" 552 | source = "registry+https://github.com/rust-lang/crates.io-index" 553 | checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" 554 | 555 | [[package]] 556 | name = "strum_macros" 557 | version = "0.24.3" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" 560 | dependencies = [ 561 | "heck", 562 | "proc-macro2", 563 | "quote", 564 | "rustversion", 565 | "syn", 566 | ] 567 | 568 | [[package]] 569 | name = "syn" 570 | version = "1.0.107" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" 573 | dependencies = [ 574 | "proc-macro2", 575 | "quote", 576 | "unicode-ident", 577 | ] 578 | 579 | [[package]] 580 | name = "syntect" 581 | version = "4.7.1" 582 | source = "registry+https://github.com/rust-lang/crates.io-index" 583 | checksum = "ec9c431748126d4e82a8ee28a29fddcc276357ebb9a67d01175633b307413496" 584 | dependencies = [ 585 | "bincode", 586 | "bitflags", 587 | "flate2", 588 | "fnv", 589 | "lazy_static", 590 | "once_cell", 591 | "onig", 592 | "plist", 593 | "regex-syntax", 594 | "serde", 595 | "serde_derive", 596 | "serde_json", 597 | "walkdir", 598 | "yaml-rust", 599 | ] 600 | 601 | [[package]] 602 | name = "term_size" 603 | version = "0.3.2" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9" 606 | dependencies = [ 607 | "libc", 608 | "winapi", 609 | ] 610 | 611 | [[package]] 612 | name = "termcolor" 613 | version = "1.1.3" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" 616 | dependencies = [ 617 | "winapi-util", 618 | ] 619 | 620 | [[package]] 621 | name = "textwrap" 622 | version = "0.11.0" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 625 | dependencies = [ 626 | "term_size", 627 | "unicode-width", 628 | ] 629 | 630 | [[package]] 631 | name = "thiserror" 632 | version = "1.0.38" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" 635 | dependencies = [ 636 | "thiserror-impl", 637 | ] 638 | 639 | [[package]] 640 | name = "thiserror-impl" 641 | version = "1.0.38" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" 644 | dependencies = [ 645 | "proc-macro2", 646 | "quote", 647 | "syn", 648 | ] 649 | 650 | [[package]] 651 | name = "thread_local" 652 | version = "1.0.1" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" 655 | dependencies = [ 656 | "lazy_static", 657 | ] 658 | 659 | [[package]] 660 | name = "toml" 661 | version = "0.5.10" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" 664 | dependencies = [ 665 | "indexmap", 666 | "serde", 667 | ] 668 | 669 | [[package]] 670 | name = "unicode-ident" 671 | version = "1.0.6" 672 | source = "registry+https://github.com/rust-lang/crates.io-index" 673 | checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" 674 | 675 | [[package]] 676 | name = "unicode-width" 677 | version = "0.1.7" 678 | source = "registry+https://github.com/rust-lang/crates.io-index" 679 | checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" 680 | 681 | [[package]] 682 | name = "unsafe-libyaml" 683 | version = "0.2.5" 684 | source = "registry+https://github.com/rust-lang/crates.io-index" 685 | checksum = "bc7ed8ba44ca06be78ea1ad2c3682a43349126c8818054231ee6f4748012aed2" 686 | 687 | [[package]] 688 | name = "vec_map" 689 | version = "0.8.2" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 692 | 693 | [[package]] 694 | name = "walkdir" 695 | version = "2.3.1" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" 698 | dependencies = [ 699 | "same-file", 700 | "winapi", 701 | "winapi-util", 702 | ] 703 | 704 | [[package]] 705 | name = "winapi" 706 | version = "0.3.8" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 709 | dependencies = [ 710 | "winapi-i686-pc-windows-gnu", 711 | "winapi-x86_64-pc-windows-gnu", 712 | ] 713 | 714 | [[package]] 715 | name = "winapi-i686-pc-windows-gnu" 716 | version = "0.4.0" 717 | source = "registry+https://github.com/rust-lang/crates.io-index" 718 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 719 | 720 | [[package]] 721 | name = "winapi-util" 722 | version = "0.1.5" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 725 | dependencies = [ 726 | "winapi", 727 | ] 728 | 729 | [[package]] 730 | name = "winapi-x86_64-pc-windows-gnu" 731 | version = "0.4.0" 732 | source = "registry+https://github.com/rust-lang/crates.io-index" 733 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 734 | 735 | [[package]] 736 | name = "windows-sys" 737 | version = "0.42.0" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" 740 | dependencies = [ 741 | "windows_aarch64_gnullvm", 742 | "windows_aarch64_msvc", 743 | "windows_i686_gnu", 744 | "windows_i686_msvc", 745 | "windows_x86_64_gnu", 746 | "windows_x86_64_gnullvm", 747 | "windows_x86_64_msvc", 748 | ] 749 | 750 | [[package]] 751 | name = "windows_aarch64_gnullvm" 752 | version = "0.42.0" 753 | source = "registry+https://github.com/rust-lang/crates.io-index" 754 | checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" 755 | 756 | [[package]] 757 | name = "windows_aarch64_msvc" 758 | version = "0.42.0" 759 | source = "registry+https://github.com/rust-lang/crates.io-index" 760 | checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" 761 | 762 | [[package]] 763 | name = "windows_i686_gnu" 764 | version = "0.42.0" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" 767 | 768 | [[package]] 769 | name = "windows_i686_msvc" 770 | version = "0.42.0" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" 773 | 774 | [[package]] 775 | name = "windows_x86_64_gnu" 776 | version = "0.42.0" 777 | source = "registry+https://github.com/rust-lang/crates.io-index" 778 | checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" 779 | 780 | [[package]] 781 | name = "windows_x86_64_gnullvm" 782 | version = "0.42.0" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" 785 | 786 | [[package]] 787 | name = "windows_x86_64_msvc" 788 | version = "0.42.0" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" 791 | 792 | [[package]] 793 | name = "xml-rs" 794 | version = "0.8.3" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "b07db065a5cf61a7e4ba64f29e67db906fb1787316516c4e6e5ff0fea1efcd8a" 797 | 798 | [[package]] 799 | name = "yaml-rust" 800 | version = "0.4.5" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" 803 | dependencies = [ 804 | "linked-hash-map", 805 | ] 806 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "refmt" 3 | version = "0.2.2" 4 | authors = ["yoshihitoh "] 5 | edition = "2021" 6 | 7 | [badges] 8 | travis-ci = { repository = "yoshihitoh/refmt" } 9 | 10 | [workspace] 11 | members = [ 12 | "refmt-serde", 13 | ] 14 | 15 | [[bin]] 16 | name = "refmt" 17 | path = "src/bin/refmt/main.rs" 18 | 19 | [[bin]] 20 | name = "refmt-generate-assets" 21 | path = "src/bin/generate_assets/main.rs" 22 | 23 | [dependencies] 24 | ansi_term = "0.12" 25 | anyhow = "1" 26 | atty = "0.2" 27 | env_logger = "0.10" 28 | log = "0.4" 29 | refmt-serde = { version = "0.3.0", path = "./refmt-serde"} 30 | strum = "0.24" 31 | strum_macros = "0.24" 32 | thiserror = "1" 33 | 34 | [dependencies.clap ] 35 | version = "2.32" 36 | features = ["suggestions", "color", "wrap_help"] 37 | 38 | [dependencies.syntect] 39 | version = "4.7" 40 | default_features = false 41 | features = ["parsing", "yaml-load", "dump-load", "dump-create", "regex-onig"] 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Yoshihito 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # refmt 2 | [![Build Status](https://travis-ci.org/yoshihitoh/refmt.svg?branch=master)](https://travis-ci.org/yoshihitoh/refmt) 3 | 4 | refmt is a data format translation tool written in Rust. Currently only JSON, YAML and TOML are available. 5 | 6 | # Syntax highlighting 7 | refmt supports syntax highlighting. 8 | 9 | ![Syntax highlighting example](https://i.imgur.com/vSlsRAC.png) 10 | 11 | # Installation 12 | refmt is written ins Rust, so you need Rust toolchains. refmt compiled with Rust 1.30.0 (stable) or newer. 13 | 14 | To build refmt: 15 | 16 | ```bash 17 | $ git clone https://github.com/yoshihitoh/refmt 18 | $ cd refmt 19 | $ cargo build --release 20 | $ ./target/release/refmt --version 21 | refmt 0.1.2 22 | ``` 23 | 24 | # Usage 25 | ``` bash 26 | $ ./target/release/refmt --help 27 | refmt 0.1.2 28 | yoshihitoh 29 | Translate data format into another one. 30 | 31 | USAGE: 32 | refmt [OPTIONS] 33 | 34 | FLAGS: 35 | -h, --help Prints help information 36 | -V, --version Prints version information 37 | 38 | OPTIONS: 39 | -i, --input set the input file to use 40 | --input-format set the name of input format [possible values: json, yaml] 41 | -o, --output set the output file to use 42 | --output-format set the name of output format [possible values: json, yaml] 43 | ``` 44 | 45 | # Examples 46 | 47 | ## JSON to YAML 48 | ``` bash 49 | $ echo '{"id": 1, "name": {"first": "John", "last": "Doe"}}' | ./target/release/refmt --input-format json --output-format yaml 50 | --- 51 | id: 1 52 | name: 53 | first: John 54 | last: Doe 55 | ``` 56 | 57 | 58 | ## YAML to JSON 59 | ``` bash 60 | $ cat < --- 62 | > id: 1 63 | > name: 64 | > first: John 65 | > last: Doe 66 | > EOS 67 | { 68 | "id": 1, 69 | "name": { 70 | "first": "John", 71 | "last": "Doe" 72 | } 73 | } 74 | ``` 75 | 76 | ## JSON to TOML 77 | ``` bash 78 | $ echo '{"id": 1, "name": {"first": "John", "last": "Doe"}}' | refmt --input-format json --output-format toml 79 | id = 1 80 | 81 | [name] 82 | first = 'John' 83 | last = 'Doe' 84 | 85 | ``` 86 | 87 | # Running tests 88 | ```bash 89 | $ cargo test --all 90 | ``` 91 | -------------------------------------------------------------------------------- /assets/create.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | ASSETS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 6 | cargo run --release --bin refmt-generate-assets -- --assets-dir "$ASSETS_DIR" 7 | -------------------------------------------------------------------------------- /assets/syntaxes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshihitoh/refmt/2007f84d502dd40a7d69cf4dd96bee4bc9a4daf6/assets/syntaxes.bin -------------------------------------------------------------------------------- /assets/themes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yoshihitoh/refmt/2007f84d502dd40a7d69cf4dd96bee4bc9a4daf6/assets/themes.bin -------------------------------------------------------------------------------- /ci/github-actions/macos-install-packages: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # nothing to do 4 | -------------------------------------------------------------------------------- /ci/github-actions/ubuntu-install-packages: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sudo apt-get update 4 | sudo apt-get install -y --no-install-recommends \ 5 | zsh xz-utils liblz4-tool musl-tools 6 | -------------------------------------------------------------------------------- /refmt-serde/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.wasm32-wasi] 2 | runner = "wasmer" 3 | -------------------------------------------------------------------------------- /refmt-serde/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.68" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" 10 | 11 | [[package]] 12 | name = "autocfg" 13 | version = "1.1.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 16 | 17 | [[package]] 18 | name = "hashbrown" 19 | version = "0.12.3" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 22 | 23 | [[package]] 24 | name = "indexmap" 25 | version = "1.9.2" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" 28 | dependencies = [ 29 | "autocfg", 30 | "hashbrown", 31 | ] 32 | 33 | [[package]] 34 | name = "itoa" 35 | version = "1.0.5" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" 38 | 39 | [[package]] 40 | name = "proc-macro2" 41 | version = "1.0.49" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" 44 | dependencies = [ 45 | "unicode-ident", 46 | ] 47 | 48 | [[package]] 49 | name = "quote" 50 | version = "1.0.23" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" 53 | dependencies = [ 54 | "proc-macro2", 55 | ] 56 | 57 | [[package]] 58 | name = "refmt-serde" 59 | version = "0.3.0" 60 | dependencies = [ 61 | "anyhow", 62 | "serde", 63 | "serde_json", 64 | "serde_yaml", 65 | "toml", 66 | ] 67 | 68 | [[package]] 69 | name = "ryu" 70 | version = "1.0.12" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" 73 | 74 | [[package]] 75 | name = "serde" 76 | version = "1.0.152" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" 79 | dependencies = [ 80 | "serde_derive", 81 | ] 82 | 83 | [[package]] 84 | name = "serde_derive" 85 | version = "1.0.152" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" 88 | dependencies = [ 89 | "proc-macro2", 90 | "quote", 91 | "syn", 92 | ] 93 | 94 | [[package]] 95 | name = "serde_json" 96 | version = "1.0.91" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" 99 | dependencies = [ 100 | "indexmap", 101 | "itoa", 102 | "ryu", 103 | "serde", 104 | ] 105 | 106 | [[package]] 107 | name = "serde_yaml" 108 | version = "0.9.16" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "92b5b431e8907b50339b51223b97d102db8d987ced36f6e4d03621db9316c834" 111 | dependencies = [ 112 | "indexmap", 113 | "itoa", 114 | "ryu", 115 | "serde", 116 | "unsafe-libyaml", 117 | ] 118 | 119 | [[package]] 120 | name = "syn" 121 | version = "1.0.107" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" 124 | dependencies = [ 125 | "proc-macro2", 126 | "quote", 127 | "unicode-ident", 128 | ] 129 | 130 | [[package]] 131 | name = "toml" 132 | version = "0.5.10" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" 135 | dependencies = [ 136 | "serde", 137 | ] 138 | 139 | [[package]] 140 | name = "unicode-ident" 141 | version = "1.0.6" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" 144 | 145 | [[package]] 146 | name = "unsafe-libyaml" 147 | version = "0.2.5" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "bc7ed8ba44ca06be78ea1ad2c3682a43349126c8818054231ee6f4748012aed2" 150 | -------------------------------------------------------------------------------- /refmt-serde/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "refmt-serde" 3 | version = "0.3.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | serde = { version = "1.0", features = ["derive"] } 10 | serde_json = { version = "1.0", features = ["preserve_order"] } 11 | serde_yaml = "0.9" 12 | thiserror = "1.0" 13 | toml = { version = "0.5", features = ["preserve_order"] } 14 | 15 | [dev-dependencies] 16 | once_cell = "1.17" 17 | -------------------------------------------------------------------------------- /refmt-serde/src/lib.rs: -------------------------------------------------------------------------------- 1 | use ::serde::Deserialize; 2 | 3 | use crate::serde::{json, toml, yaml, Serde}; 4 | 5 | pub mod serde; 6 | 7 | #[derive(Debug, Copy, Clone)] 8 | pub enum Format { 9 | Json, 10 | Toml, 11 | Yaml, 12 | } 13 | 14 | #[derive(Debug, thiserror::Error)] 15 | pub enum RefmtError { 16 | #[error("json error.")] 17 | Json(#[from] ::Error), 18 | 19 | #[error("toml error.")] 20 | Toml(#[from] ::Error), 21 | 22 | #[error("yaml error.")] 23 | Yaml(#[from] ::Error), 24 | } 25 | 26 | pub struct Refmt { 27 | pub src_format: Format, 28 | pub dest_format: Format, 29 | } 30 | 31 | impl Refmt { 32 | pub fn refmt(&self, s: &str) -> Result { 33 | let r = match self.dest_format { 34 | Format::Json => self.to_json(s)?, 35 | Format::Toml => self.to_toml(s)?, 36 | Format::Yaml => self.to_yaml(s)?, 37 | }; 38 | Ok(r) 39 | } 40 | 41 | fn to_json(&self, s: &str) -> Result { 42 | let v = self.deserialize::<::ValueType>(s)?; 43 | let s = json::Json.serialize(&v)?; 44 | Ok(s) 45 | } 46 | 47 | fn to_toml(&self, s: &str) -> Result { 48 | let v = self.deserialize::<::ValueType>(s)?; 49 | let s = toml::Toml.serialize(&v)?; 50 | Ok(s) 51 | } 52 | 53 | fn to_yaml(&self, s: &str) -> Result { 54 | let v = self.deserialize::<::ValueType>(s)?; 55 | let s = yaml::Yaml.serialize(&v)?; 56 | Ok(s) 57 | } 58 | 59 | fn deserialize(&self, s: &str) -> Result 60 | where 61 | T: for<'de> Deserialize<'de>, 62 | { 63 | let r = match self.src_format { 64 | Format::Json => json::Json.deserialize(s)?, 65 | Format::Toml => toml::Toml.deserialize(s)?, 66 | Format::Yaml => yaml::Yaml.deserialize(s)?, 67 | }; 68 | Ok(r) 69 | } 70 | } 71 | 72 | #[cfg(test)] 73 | mod tests { 74 | mod fixtures { 75 | use once_cell::sync::Lazy; 76 | pub static JSON: Lazy = Lazy::new(|| { 77 | r#" 78 | { 79 | "id": 123, 80 | "title": "Lorem ipsum dolor sit amet", 81 | "author": { 82 | "id": 999, 83 | "first_name": "John", 84 | "last_name": "Doe" 85 | } 86 | } 87 | "# 88 | .trim_start() 89 | .to_string() 90 | }); 91 | 92 | pub static TOML: Lazy = Lazy::new(|| { 93 | r#" 94 | id = 123 95 | title = "Lorem ipsum dolor sit amet" 96 | 97 | [author] 98 | id = 999 99 | first_name = "John" 100 | last_name = "Doe" 101 | "# 102 | .trim_start() 103 | .to_string() 104 | }); 105 | 106 | pub static YAML: Lazy = Lazy::new(|| { 107 | // 108 | r#" 109 | id: 123 110 | title: Lorem ipsum dolor sit amet 111 | author: 112 | id: 999 113 | first_name: John 114 | last_name: Doe 115 | "# 116 | .trim_start() 117 | .to_string() 118 | }); 119 | } 120 | 121 | use crate::{Format, Refmt}; 122 | use fixtures::{JSON, TOML, YAML}; 123 | 124 | fn refmt(src_format: Format, dest_format: Format) -> Refmt { 125 | Refmt { 126 | src_format, 127 | dest_format, 128 | } 129 | } 130 | 131 | #[test] 132 | fn json_to_json() { 133 | let refmt = refmt(Format::Json, Format::Json); 134 | let r = refmt.refmt(&JSON); 135 | assert_eq!(Some(JSON.to_string()), r.ok()); 136 | } 137 | 138 | #[test] 139 | fn json_to_toml() { 140 | let refmt = refmt(Format::Json, Format::Toml); 141 | let r = refmt.refmt(&JSON); 142 | assert_eq!(Some(TOML.to_string()), r.ok()); 143 | } 144 | 145 | #[test] 146 | fn json_to_yaml() { 147 | let refmt = refmt(Format::Json, Format::Yaml); 148 | let r = refmt.refmt(&JSON); 149 | assert_eq!(Some(YAML.to_string()), r.ok()); 150 | } 151 | 152 | #[test] 153 | fn toml_to_json() { 154 | let refmt = refmt(Format::Toml, Format::Json); 155 | let r = refmt.refmt(&TOML); 156 | assert_eq!(Some(JSON.to_string()), r.ok()); 157 | } 158 | 159 | #[test] 160 | fn toml_to_toml() { 161 | let refmt = refmt(Format::Toml, Format::Toml); 162 | let r = refmt.refmt(&TOML); 163 | assert_eq!(Some(TOML.to_string()), r.ok()); 164 | } 165 | 166 | #[test] 167 | fn toml_to_yaml() { 168 | let refmt = refmt(Format::Toml, Format::Yaml); 169 | let r = refmt.refmt(&TOML); 170 | assert_eq!(Some(YAML.to_string()), r.ok()); 171 | } 172 | 173 | #[test] 174 | fn yaml_to_json() { 175 | let refmt = refmt(Format::Yaml, Format::Json); 176 | let r = refmt.refmt(&YAML); 177 | assert_eq!(Some(JSON.to_string()), r.ok()); 178 | } 179 | 180 | #[test] 181 | fn yaml_to_toml() { 182 | let refmt = refmt(Format::Yaml, Format::Toml); 183 | let r = refmt.refmt(&YAML); 184 | assert_eq!(Some(TOML.to_string()), r.ok()); 185 | } 186 | 187 | #[test] 188 | fn yaml_to_yaml() { 189 | let refmt = refmt(Format::Yaml, Format::Yaml); 190 | let r = refmt.refmt(&YAML); 191 | assert_eq!(Some(YAML.to_string()), r.ok()); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /refmt-serde/src/serde/json.rs: -------------------------------------------------------------------------------- 1 | use super::Serde; 2 | use serde::Deserialize; 3 | 4 | pub struct Json; 5 | 6 | impl Serde for Json { 7 | type Error = serde_json::Error; 8 | type ValueType = serde_json::Value; 9 | 10 | fn serialize(&self, v: &Self::ValueType) -> Result { 11 | let mut s = serde_json::to_string_pretty(v)?; 12 | s.push('\n'); // add a new-line for consistency. (YAML and TOML have a new-line on its tail.) 13 | Ok(s) 14 | } 15 | 16 | fn deserialize Deserialize<'de>>(&self, s: &str) -> Result { 17 | let v = serde_json::from_str(s)?; 18 | Ok(v) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /refmt-serde/src/serde/mod.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | pub mod json; 4 | pub mod toml; 5 | pub mod yaml; 6 | 7 | pub trait Serde { 8 | type Error: std::error::Error; 9 | type ValueType: Serialize; 10 | 11 | fn serialize(&self, v: &Self::ValueType) -> Result; 12 | fn deserialize Deserialize<'de>>(&self, s: &str) -> Result; 13 | } 14 | -------------------------------------------------------------------------------- /refmt-serde/src/serde/toml.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | 3 | use super::Serde; 4 | 5 | #[derive(Debug, thiserror::Error)] 6 | pub enum TomlError { 7 | #[error("can't serialize into toml.")] 8 | Serialize(#[from] toml::ser::Error), 9 | 10 | #[error("can't deserialize from toml.")] 11 | Deserialize(#[from] toml::de::Error), 12 | } 13 | 14 | pub struct Toml; 15 | 16 | impl Serde for Toml { 17 | type Error = TomlError; 18 | type ValueType = toml::Value; 19 | 20 | fn serialize(&self, v: &Self::ValueType) -> Result { 21 | let s = toml::to_string(v)?; 22 | Ok(s) 23 | } 24 | 25 | fn deserialize Deserialize<'de>>(&self, s: &str) -> Result { 26 | let v = toml::from_str(s)?; 27 | Ok(v) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /refmt-serde/src/serde/yaml.rs: -------------------------------------------------------------------------------- 1 | use super::Serde; 2 | use serde::Deserialize; 3 | 4 | pub struct Yaml; 5 | 6 | impl Serde for Yaml { 7 | type Error = serde_yaml::Error; 8 | type ValueType = serde_yaml::Value; 9 | 10 | fn serialize(&self, v: &Self::ValueType) -> Result { 11 | let s = serde_yaml::to_string(v)?; 12 | Ok(s) 13 | } 14 | 15 | fn deserialize Deserialize<'de>>(&self, s: &str) -> Result { 16 | let v = serde_yaml::from_str(s)?; 17 | Ok(v) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/assets.rs: -------------------------------------------------------------------------------- 1 | use syntect::highlighting::{Theme, ThemeSet}; 2 | use syntect::parsing::{SyntaxReference, SyntaxSet}; 3 | 4 | const DEFAULT_THEME: &str = "Monokai Extended"; 5 | const JSON_THEME: &str = "Monokai JSON+"; 6 | 7 | pub struct HighlightAssets { 8 | pub syntax_set: SyntaxSet, 9 | pub theme_set: ThemeSet, 10 | } 11 | 12 | impl HighlightAssets { 13 | pub fn new(syntax_set: SyntaxSet, theme_set: ThemeSet) -> HighlightAssets { 14 | HighlightAssets { 15 | syntax_set, 16 | theme_set, 17 | } 18 | } 19 | 20 | pub fn get_syntax(&self, name: &str) -> &SyntaxReference { 21 | self.syntax_set.find_syntax_by_extension(name).unwrap() 22 | } 23 | 24 | pub fn syntaxes(&self) -> &[SyntaxReference] { 25 | self.syntax_set.syntaxes() 26 | } 27 | 28 | pub fn get_default_theme(&self) -> &Theme { 29 | self.get_theme(DEFAULT_THEME) 30 | } 31 | 32 | pub fn get_theme(&self, name: &str) -> &Theme { 33 | &self.theme_set.themes[name] 34 | } 35 | 36 | pub fn get_theme_for_syntax(&self, syntax: &SyntaxReference) -> &Theme { 37 | self.get_theme(if syntax.name.to_ascii_lowercase() == "json" { 38 | JSON_THEME 39 | } else { 40 | DEFAULT_THEME 41 | }) 42 | } 43 | 44 | pub fn themes(&self) -> Vec<&Theme> { 45 | self.theme_set.themes.iter().map(|(_, v)| v).collect() 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/bin/generate_assets/main.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | 3 | use anyhow::{anyhow, Context}; 4 | use clap::{App, Arg}; 5 | use syntect::dumps::dump_to_file; 6 | use syntect::highlighting::ThemeSet; 7 | use syntect::parsing::{SyntaxSet, SyntaxSetBuilder}; 8 | 9 | use refmt::assets::HighlightAssets; 10 | 11 | struct AssetBuilder {} 12 | 13 | impl AssetBuilder { 14 | pub fn build_from_files( 15 | syntaxes_dir: &Path, 16 | themes_dir: &Path, 17 | ) -> Result { 18 | let builder = AssetBuilder::default(); 19 | Ok(HighlightAssets { 20 | syntax_set: builder.build_syntaxes(syntaxes_dir)?, 21 | theme_set: builder.build_themes(themes_dir)?, 22 | }) 23 | } 24 | 25 | pub fn save(assets: HighlightAssets, assets_dir: &Path) -> Result<(), anyhow::Error> { 26 | dump_to_file(&assets.syntax_set, assets_dir.join("syntaxes.bin")) 27 | .context("Cannot create assets sytaxes.bin")?; 28 | dump_to_file(&assets.theme_set, assets_dir.join("themes.bin")) 29 | .context("Cannot create assets theme.bin")?; 30 | 31 | Ok(()) 32 | } 33 | 34 | fn build_syntaxes(&self, syntaxes_dir: &Path) -> Result { 35 | let mut syntax_set_builder = SyntaxSetBuilder::new(); 36 | syntax_set_builder.add_plain_text_syntax(); 37 | syntax_set_builder 38 | .add_from_folder(syntaxes_dir, true) 39 | .map_err(|e| anyhow!("Cannot create syntaxes. error:{:?}", e))?; 40 | 41 | Ok(syntax_set_builder.build()) 42 | } 43 | 44 | fn build_themes(&self, themes_dir: &Path) -> Result { 45 | let mut theme_set = ThemeSet::default(); 46 | theme_set 47 | .add_from_folder(themes_dir) 48 | .map_err(|e| anyhow!("Cannot create themes. error:{:?}", e))?; 49 | 50 | Ok(theme_set) 51 | } 52 | } 53 | 54 | impl Default for AssetBuilder { 55 | fn default() -> Self { 56 | AssetBuilder {} 57 | } 58 | } 59 | 60 | #[derive(Debug)] 61 | struct ProgramOption { 62 | assets_dir: String, 63 | } 64 | 65 | fn parse_args() -> ProgramOption { 66 | let m = App::new("generate_assets") 67 | .arg( 68 | Arg::with_name("ASSETS_DIR") 69 | .long("assets-dir") 70 | .help("Set path to assets directory") 71 | .takes_value(true) 72 | .value_name("ASSETS_DIR") 73 | .required(true), 74 | ) 75 | .get_matches(); 76 | 77 | ProgramOption { 78 | assets_dir: m.value_of("ASSETS_DIR").unwrap().to_string(), 79 | } 80 | } 81 | 82 | fn main() -> Result<(), Box> { 83 | let options = parse_args(); 84 | let assets_dir = Path::new(&options.assets_dir); 85 | let assets = 86 | AssetBuilder::build_from_files(&assets_dir.join("syntaxes"), &assets_dir.join("themes"))?; 87 | AssetBuilder::save(assets, Path::new(&options.assets_dir))?; 88 | Ok(()) 89 | } 90 | -------------------------------------------------------------------------------- /src/bin/refmt/app.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write}; 3 | use std::path::Path; 4 | use std::str::FromStr; 5 | 6 | use clap::{crate_authors, crate_name, crate_version, App as ClapApp, AppSettings, Arg}; 7 | use log::debug; 8 | use syntect::dumps::from_binary; 9 | 10 | use refmt::assets::HighlightAssets; 11 | use refmt::errors; 12 | use refmt::format::{FileFormat, FormattedText}; 13 | 14 | use crate::printer::{HighlightTextPrinter, PlainTextPrinter, Printer}; 15 | 16 | #[derive(Debug)] 17 | struct Config { 18 | input_file: Option, 19 | input_format: FileFormat, 20 | output_file: Option, 21 | output_format: FileFormat, 22 | color_enabled: bool, 23 | theme_name: String, 24 | } 25 | 26 | fn infer_format_name<'a>(file: Option<&'a str>, format_name: Option<&'a str>) -> Option<&'a str> { 27 | if let Some(format_name) = format_name { 28 | Some(format_name) 29 | } else if let Some(file) = file { 30 | Path::new(file).extension().and_then(|ext| ext.to_str()) 31 | } else { 32 | None 33 | } 34 | } 35 | 36 | fn infer_format( 37 | file: Option<&str>, 38 | format_name: Option<&str>, 39 | ) -> Result { 40 | let format_name = infer_format_name(file, format_name); 41 | if let Some(format_name) = format_name { 42 | FileFormat::from_str(format_name) 43 | } else { 44 | Err(errors::Error::InferFormat) 45 | } 46 | } 47 | 48 | impl Config { 49 | fn new(app: ClapApp, color_enabled: bool) -> Result { 50 | let matches = app.get_matches(); 51 | let input_file = matches.value_of("INPUT_FILE"); 52 | debug!("input_file: {:?}", input_file); 53 | 54 | let input_format = matches.value_of("INPUT_FORMAT"); 55 | debug!("input_format: {:?}", input_format); 56 | let input_format = infer_format(input_file, input_format)?; 57 | 58 | let output_file = matches.value_of("OUTPUT_FILE"); 59 | debug!("output_file: {:?}", output_file); 60 | 61 | let output_format = matches.value_of("OUTPUT_FORMAT"); 62 | debug!("output_format: {:?}", output_format); 63 | let output_format = infer_format_name(output_file, output_format) 64 | .map(FileFormat::from_str) 65 | .unwrap_or_else(|| Ok(input_format))?; 66 | 67 | let theme_name = "Monokai Extended"; 68 | Ok(Config { 69 | input_file: input_file.map(|s| s.to_string()), 70 | input_format, 71 | output_file: output_file.map(|s| s.to_string()), 72 | output_format, 73 | color_enabled: color_enabled, 74 | theme_name: theme_name.to_string(), 75 | }) 76 | } 77 | } 78 | 79 | fn build_clap_app(color_enabled: bool) -> clap::App<'static, 'static> { 80 | let color_setting = if color_enabled { 81 | AppSettings::ColoredHelp 82 | } else { 83 | AppSettings::ColorNever 84 | }; 85 | 86 | ClapApp::new(crate_name!()) 87 | .about("reformat between JSON, YAML and TOML.") 88 | .author(crate_authors!()) 89 | .version(crate_version!()) 90 | .global_setting(color_setting) 91 | .arg( 92 | Arg::with_name("INPUT_FILE") 93 | .help("set the input file to use. Assume STDIN if omitted") 94 | .short("i") 95 | .long("input") 96 | .takes_value(true) 97 | .value_name("FILE"), 98 | ) 99 | .arg( 100 | Arg::with_name("INPUT_FORMAT") 101 | .help("set the name of input format. Assume format by file extension if omitted.") 102 | .long("input-format") 103 | .takes_value(true) 104 | .value_name("FORMAT_NAME") 105 | .case_insensitive(true) 106 | .possible_values(&FileFormat::names()), 107 | ) 108 | .arg( 109 | Arg::with_name("OUTPUT_FILE") 110 | .help("set the output file to use. Assume STDOUT if omitted") 111 | .short("o") 112 | .long("output") 113 | .takes_value(true) 114 | .value_name("FILE"), 115 | ) 116 | .arg( 117 | Arg::with_name("OUTPUT_FORMAT") 118 | .help("set the name of output format. Assume format by file extension if omitted") 119 | .long("output-format") 120 | .takes_value(true) 121 | .value_name("FORMAT_NAME") 122 | .case_insensitive(true) 123 | .possible_values(&FileFormat::names()), 124 | ) 125 | } 126 | 127 | pub struct App { 128 | config: Config, 129 | assets: HighlightAssets, 130 | } 131 | 132 | impl App { 133 | pub fn new() -> Result { 134 | let color_enabled = atty::is(atty::Stream::Stdout); 135 | let config = Config::new(build_clap_app(color_enabled), color_enabled)?; 136 | let assets = App::load_integrated_assets(); 137 | 138 | debug!("config: {:?}", config); 139 | debug!( 140 | "syntaxes: {:?}", 141 | assets 142 | .syntaxes() 143 | .iter() 144 | .map(|s| s.name.as_str()) 145 | .collect::>() 146 | ); 147 | debug!( 148 | "themes: {:?}", 149 | assets 150 | .themes() 151 | .iter() 152 | .map(|&t| t 153 | .name 154 | .as_ref() 155 | .map(|s| s.as_str()) 156 | .unwrap_or("** unnamed theme **")) 157 | .collect::>() 158 | ); 159 | Ok(App { config, assets }) 160 | } 161 | 162 | pub fn run(&self) -> Result<(), errors::Error> { 163 | let input_text = self.read_from_input()?; 164 | let output_text = input_text.convert_to(self.config.output_format)?; 165 | 166 | self.write_to_output(&output_text) 167 | } 168 | 169 | fn load_integrated_assets() -> HighlightAssets { 170 | HighlightAssets::new( 171 | from_binary(include_bytes!("../../../assets/syntaxes.bin")), 172 | from_binary(include_bytes!("../../../assets/themes.bin")), 173 | ) 174 | } 175 | 176 | fn read_from_input(&self) -> Result { 177 | // open reader 178 | let stdin = stdin(); 179 | let lock = stdin.lock(); 180 | let mut reader = if let Some(f) = self.config.input_file.as_ref() { 181 | Box::new(BufReader::new(File::open(f)?)) as Box 182 | } else { 183 | Box::new(lock) as Box 184 | }; 185 | 186 | // read 187 | let mut text = String::new(); 188 | reader.read_to_string(&mut text)?; 189 | 190 | Ok(FormattedText::new(self.config.input_format, text)) 191 | } 192 | 193 | fn write_to_output(&self, text: &FormattedText) -> Result<(), errors::Error> { 194 | // open writer 195 | let stdout = stdout(); 196 | let lock = stdout.lock(); 197 | let mut w = if let Some(f) = self.config.output_file.as_ref() { 198 | Box::new(BufWriter::new(File::create(f)?)) as Box 199 | } else { 200 | Box::new(lock) as Box 201 | }; 202 | 203 | // select printer 204 | let printer = if self.config.output_file.is_none() && self.config.color_enabled { 205 | Box::new(HighlightTextPrinter::new(&self.assets)) as Box 206 | } else { 207 | Box::new(PlainTextPrinter::default()) as Box 208 | }; 209 | 210 | // print 211 | printer.print(&mut w, text) 212 | } 213 | } 214 | 215 | #[cfg(test)] 216 | mod tests { 217 | use syntect::dumps::from_reader; 218 | use syntect::highlighting::ThemeSet; 219 | use syntect::parsing::SyntaxSet; 220 | 221 | #[test] 222 | fn syntax_set_asset() -> anyhow::Result<()> { 223 | let bytes: &[u8] = include_bytes!("../../../assets/syntaxes.bin"); 224 | let _syntaxes: SyntaxSet = from_reader(bytes)?; 225 | Ok(()) 226 | } 227 | 228 | #[test] 229 | fn theme_set_asset() -> anyhow::Result<()> { 230 | let bytes: &[u8] = include_bytes!("../../../assets/themes.bin"); 231 | let _themes: ThemeSet = from_reader(bytes)?; 232 | Ok(()) 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/bin/refmt/main.rs: -------------------------------------------------------------------------------- 1 | use std::process; 2 | 3 | use refmt::errors; 4 | 5 | mod app; 6 | mod printer; 7 | 8 | fn handle_error(error: &errors::Error) { 9 | use ansi_term::Color::Red; 10 | let label = Red.paint("[refmt error]"); 11 | eprintln!("{}: {}.", label, error); 12 | } 13 | 14 | fn initialize() { 15 | env_logger::init(); 16 | } 17 | 18 | fn terminate(code: i32) { 19 | process::exit(code) 20 | } 21 | 22 | fn run() -> Result<(), errors::Error> { 23 | let app = app::App::new()?; 24 | app.run() 25 | } 26 | 27 | fn main() { 28 | initialize(); 29 | 30 | let code = match run() { 31 | Ok(()) => 0, 32 | Err(e) => { 33 | handle_error(&e); 34 | 1 35 | } 36 | }; 37 | 38 | terminate(code); 39 | } 40 | -------------------------------------------------------------------------------- /src/bin/refmt/printer.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | use syntect::easy::HighlightLines; 4 | use syntect::util::as_24_bit_terminal_escaped; 5 | 6 | use refmt::assets::HighlightAssets; 7 | use refmt::errors; 8 | use refmt::format::FormattedText; 9 | 10 | pub trait Printer { 11 | fn print(&self, dest: &mut dyn Write, text: &FormattedText) -> Result<(), errors::Error>; 12 | } 13 | 14 | pub struct PlainTextPrinter {} 15 | 16 | impl Default for PlainTextPrinter { 17 | fn default() -> Self { 18 | PlainTextPrinter {} 19 | } 20 | } 21 | 22 | impl Printer for PlainTextPrinter { 23 | fn print(&self, dest: &mut dyn Write, text: &FormattedText) -> Result<(), errors::Error> { 24 | Ok(write!(dest, "{}", text.text.as_str()).map_err(errors::Error::Io)?) 25 | } 26 | } 27 | 28 | pub struct HighlightTextPrinter<'a> { 29 | assets: &'a HighlightAssets, 30 | } 31 | 32 | impl<'a> HighlightTextPrinter<'a> { 33 | pub fn new(assets: &'a HighlightAssets) -> Self { 34 | HighlightTextPrinter { assets } 35 | } 36 | } 37 | 38 | impl<'a> Printer for HighlightTextPrinter<'a> { 39 | fn print(&self, dest: &mut dyn Write, text: &FormattedText) -> Result<(), errors::Error> { 40 | let syntax = self.assets.get_syntax(text.format.preferred_extension()); 41 | let theme = self.assets.get_theme_for_syntax(syntax); 42 | let mut highlight = HighlightLines::new(syntax, theme); 43 | let ranges = highlight.highlight(&text.text, &self.assets.syntax_set); 44 | let escaped = as_24_bit_terminal_escaped(&ranges, true); 45 | Ok(write!(dest, "{}", escaped).map_err(errors::Error::from)?) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/errors.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | use refmt_serde::RefmtError; 4 | use thiserror::Error; 5 | 6 | #[derive(Debug, Error)] 7 | pub enum Error { 8 | #[error("IO Error. cause:{_0}")] 9 | Io(#[from] io::Error), 10 | 11 | #[error("Any errors occurred on re-format. cause:{_0}")] 12 | RefmtError(#[from] RefmtError), 13 | 14 | #[error("Unsupported format name. name:{_0}")] 15 | FormatName(String), 16 | 17 | #[error("Cannot infer format. Please specify either FILE or FORMAT")] 18 | InferFormat, 19 | 20 | #[error("Cannot create assets")] 21 | CreatingAssets(String), 22 | } 23 | -------------------------------------------------------------------------------- /src/format.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | use refmt_serde::{Format, Refmt}; 4 | use strum::IntoEnumIterator; 5 | use strum_macros::EnumIter; 6 | 7 | use crate::errors; 8 | 9 | #[derive(Copy, Clone, Debug, Eq, PartialEq, EnumIter)] 10 | pub enum FileFormat { 11 | Json, 12 | Toml, 13 | Yaml, 14 | } 15 | 16 | impl FileFormat { 17 | pub fn names() -> Vec<&'static str> { 18 | FileFormat::iter().map(|f| f.name()).collect() 19 | } 20 | 21 | pub fn name(&self) -> &'static str { 22 | match *self { 23 | FileFormat::Json => "json", 24 | FileFormat::Toml => "toml", 25 | FileFormat::Yaml => "yaml", 26 | } 27 | } 28 | 29 | pub fn extensions(&self) -> &[&'static str] { 30 | match *self { 31 | FileFormat::Json => &["json"], 32 | FileFormat::Toml => &["toml"], 33 | FileFormat::Yaml => &["yaml", "yml"], 34 | } 35 | } 36 | 37 | pub fn is_extension(&self, s: &str) -> bool { 38 | self.extensions().iter().find(|&&ext| ext == s).is_some() 39 | } 40 | 41 | pub fn preferred_extension(&self) -> &'static str { 42 | self.name() 43 | } 44 | } 45 | 46 | impl FromStr for FileFormat { 47 | type Err = errors::Error; 48 | 49 | fn from_str(s: &str) -> Result::Err> { 50 | let lower = s.to_ascii_lowercase(); 51 | Ok(FileFormat::iter() 52 | .find(|f| f.is_extension(&lower)) 53 | .ok_or(errors::Error::FormatName(s.to_string()))?) 54 | } 55 | } 56 | 57 | impl From for Format { 58 | fn from(value: FileFormat) -> Self { 59 | match value { 60 | FileFormat::Json => Format::Json, 61 | FileFormat::Yaml => Format::Yaml, 62 | FileFormat::Toml => Format::Toml, 63 | } 64 | } 65 | } 66 | 67 | pub struct FormattedText { 68 | pub format: FileFormat, 69 | pub text: String, 70 | } 71 | 72 | impl FormattedText { 73 | pub fn new(format: FileFormat, text: String) -> FormattedText { 74 | FormattedText { format, text } 75 | } 76 | 77 | pub fn convert_to(&self, format: FileFormat) -> Result { 78 | let refmt = Refmt { 79 | src_format: Format::from(self.format), 80 | dest_format: Format::from(format), 81 | }; 82 | 83 | let text = refmt.refmt(&self.text)?; 84 | Ok(FormattedText { text, format }) 85 | } 86 | } 87 | 88 | #[cfg(test)] 89 | mod tests { 90 | use super::*; 91 | 92 | static JSON_TEXT: &'static str = r#"{ 93 | "id": 123, 94 | "title": "Lorem ipsum dolor sit amet", 95 | "author": { 96 | "id": 999, 97 | "first_name": "John", 98 | "last_name": "Doe" 99 | } 100 | } 101 | "#; 102 | 103 | static YAML_TEXT: &'static str = r#"id: 123 104 | title: Lorem ipsum dolor sit amet 105 | author: 106 | id: 999 107 | first_name: John 108 | last_name: Doe 109 | "#; 110 | 111 | #[test] 112 | fn format_from_str() { 113 | assert_eq!(FileFormat::Json, FileFormat::from_str("json").unwrap()); 114 | assert_eq!(FileFormat::Json, FileFormat::from_str("JsOn").unwrap()); 115 | 116 | assert_eq!(FileFormat::Toml, FileFormat::from_str("toml").unwrap()); 117 | assert_eq!(FileFormat::Yaml, FileFormat::from_str("yaml").unwrap()); 118 | assert_eq!(FileFormat::Yaml, FileFormat::from_str("yml").unwrap()); 119 | 120 | let r = FileFormat::from_str("conf"); // HOCON 121 | assert!(r.is_err()); 122 | } 123 | 124 | #[test] 125 | fn convert_json() { 126 | let text = FormattedText::new(FileFormat::Json, JSON_TEXT.to_string()); 127 | 128 | // JSON => TOML 129 | let r = text.convert_to(FileFormat::Toml); 130 | assert!(r.is_ok()); 131 | assert_eq!( 132 | r#"id = 123 133 | title = "Lorem ipsum dolor sit amet" 134 | 135 | [author] 136 | id = 999 137 | first_name = "John" 138 | last_name = "Doe" 139 | "#, 140 | r.as_ref().ok().unwrap().text 141 | ); 142 | 143 | // JSON => YAML 144 | let r = text.convert_to(FileFormat::Yaml); 145 | assert!(r.is_ok()); 146 | assert_eq!(YAML_TEXT, r.as_ref().ok().unwrap().text); 147 | 148 | // Error 149 | let text = FormattedText::new(FileFormat::Json, YAML_TEXT.to_string()); 150 | let r = text.convert_to(FileFormat::Toml); 151 | assert!(r.is_err()); 152 | } 153 | 154 | #[test] 155 | fn convert_toml() { 156 | let text = FormattedText::new( 157 | FileFormat::Toml, 158 | r#"id = 123 159 | title = "Lorem ipsum dolor sit amet" 160 | 161 | [author] 162 | id = 999 163 | first_name = "John" 164 | last_name = "Doe" 165 | "# 166 | .to_string(), 167 | ); 168 | 169 | // TOML => JSON 170 | let r = text.convert_to(FileFormat::Json); 171 | assert!(r.is_ok()); 172 | assert_eq!(JSON_TEXT, r.as_ref().ok().unwrap().text); 173 | 174 | // TOML => YAML 175 | let r = text.convert_to(FileFormat::Yaml); 176 | assert!(r.is_ok()); 177 | assert_eq!(YAML_TEXT, r.as_ref().ok().unwrap().text); 178 | 179 | // Error 180 | let text = FormattedText::new(FileFormat::Toml, JSON_TEXT.to_string()); 181 | let r = text.convert_to(FileFormat::Yaml); 182 | assert!(r.is_err()); 183 | } 184 | 185 | #[test] 186 | fn convert_yaml() { 187 | let text = FormattedText::new(FileFormat::Yaml, YAML_TEXT.to_string()); 188 | 189 | // YAML => JSON 190 | let r = text.convert_to(FileFormat::Json); 191 | assert!(r.is_ok()); 192 | assert_eq!(JSON_TEXT, r.as_ref().ok().unwrap().text); 193 | 194 | // YAML => TOML 195 | let r = text.convert_to(FileFormat::Toml); 196 | assert!(r.is_ok()); 197 | assert_eq!( 198 | r#"id = 123 199 | title = "Lorem ipsum dolor sit amet" 200 | 201 | [author] 202 | id = 999 203 | first_name = "John" 204 | last_name = "Doe" 205 | "#, 206 | r.as_ref().ok().unwrap().text 207 | ); 208 | 209 | // Error 210 | // TODO: this test will be panicked on `r.is_err()`. need to survey why the panic occurs.. 211 | // let text = FormattedText::new(Format::Yaml, TOML_TEXT.to_string()); 212 | // let r = text.convert_to(Format::Json); 213 | // assert!(r.is_err()); 214 | // assert_eq!(errors::ErrorKind::Deserialization, r.err().unwrap().kind()); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod assets; 2 | pub mod errors; 3 | pub mod format; 4 | --------------------------------------------------------------------------------