アイディア倉庫

Visual Studio Codeでなんでもこなすのがポリシー。LaTeX(2020/7/19~), C(2021/1/25~), C#(2/4~), HTML&CSS(2/14~), Python(2/16~), JavaScript(2/28~), jQuery(3/18~), Sass(Scss)(3/20~),シェルスクリプト(3/21~)

vscodeでのDart Sass開発環境構築、さらにシェルスクリプトで全自動化【Autoprefixer使用・Compass共存可】

Webサイト制作本を何冊か読み、『先ほどのCSSをコピペして〜』という記述に若干の反発を感じ始めた頃、Sassの存在を知った。

Sassを使うと一般的なプログラミング言語のような分岐処理、繰り返し処理、演算などを使ってCSSを書くことができる。念願の脱コピペ。やっぱりみんな考えることは一緒だよね…

Compassの使用方針について

Compassのサポートは2016年に終了しているので、今から使い始めるのは推奨されていない。
この記事では、基本的に雛形作成(ディレクトリの整理整頓)のためだけにCompassを利用し、Compassを使わない場合にも似たようなディレクトリ構成が用意されるようにコードの修正点を明記していく。

Sassのコンパイルには、速度が遅いCompassコマンドは使用せず、これからも新機能が増築されていく最新のDart Sassを用いる。

しかし、どんどん新たなツールが生み出されているとはいえ、CSSスプライト作成機能など、未だCompassにしかない機能もいくつかあるらしい。そんなわけで、いつでもCompassも使えるように環境だけは残しておくことにする。

インストールするもの

Visual Studio Code(この記事では必須)
コードを編集するためのテキストエディタテキストエディタとは名ばかりで、実際のところこれ一つでなんでもできる統合開発環境
普通、統合開発環境といえば各言語専用だが、VScodeは本当になんでもできる。今のところ、C, C++, C#, Python, JavaScript, Ruby, HTML, CSS, Sass(Scss), LaTeX…などあらゆる言語をここで編集し、実行できている。
適当にググってカスタマイズしてほしい。
node.js(この記事では必須)
node.jsをインストールすると使えるようになるnpmコマンドがこの記事では(というかいろいろな場面で)必須になる。
インストール方法はOSによって異なるようなので、ググって…
Dart SassやAutoprefixerはPC本体には格納せず、npmコマンドでその都度ローカルインストール(自分で作ったSassコードなどと一緒に共有できるように作業ディレクトリにインストール)するので、Compassと共存させない場合はこれ以上のインストール作業は必要ない。
RubyCompassと共存させる場合)
Sassコードをコンパイル(ブラウザが認識可能なCSSに変換)するために必要。
Macは最初から入っているのでスルー。Windowsの方は申し訳ないがググって…
Sass(Compassと共存させる場合)
CSSプログラミング言語のように効率的に書ける言語。
黒い画面からgem install sassでインストールできるはず。Macの方はsudoを先頭につけて。
compassCompassと共存させる場合)
Sassで使える便利グッズ集(Sassのミックスインや関数をライブラリ化したもの)。Sassのコンパイラとしても使える。
黒い画面からgem install compassでインストールできるはず。Macの方はsudoを先頭につけて。
autoprefixer-railsCompassと共存させる場合)
CSSベンダープレフィックス(ブラウザごとの表示の差異をなくすために必要なコード)を自動で追加してくれるツール。
黒い画面からgem install autoprefixer-railsでインストールできるはず。Macの方はsudoを先頭につけて。
csso-railsCompassと共存させる場合)
CSS縮小化ツール。別に入れなくてもよさそうだけど一応…
黒い画面からgem install csso-railsでインストールできるはず。Macの方はsudoを先頭につけて。

npmの意義

npmでは一つのアプリケーションを構成するソースファイルetc.を集めたフォルダをパッケージという。

ここではあえてソースファイルetc.と書いた。
npmの凄いところは、自分で書いたソースファイルだけでなく、それをコンパイルするコンパイラなども含めて一つのアプリケーションとしてまとめられるところだ。

例えば、作ったアプリケーションを人に提供するとき、中身がHTML, CSS, Javascriptのみであれば、相手のPCでもすぐにブラウザで実行できるだろう。
しかし、TypeScriptで書かれたファイルなどは、JavaScriptコンパイルしなければ実行できない。相手にわざわざ『TypeScriptのコンパイラをインストールしておいてね』と伝えなくてはならない。これは面倒くさい。

そこでnpmが活躍する。npmでは、ローカルインストールという機能によって、コンパイラなどを好きなディレクトリにインストールすることができる。
アプリケーションをコンパイラとセットで相手に渡せば、相手の環境にかかわらずそれを実行できる。
また、コンパイルのためのコマンドは、オプション指定などで長くなることも多い。npmでは、それらのコマンドを短いコマンドに置き換えられるように、そのパッケージ専用の独自のコマンドを設定することができる。

これから行う工程の目的はこれくらいで理解できるはず。もっと詳しく学びたい方にはこちらの記事をお勧めしておく。(まだ私も読んでいる途中)

Dart Sassをコンパイルするまでの道のり

さて、新しいnpmパッケージを作成してSassをコンパイルするまでの道のりは、結構面倒なものである。

  1. パッケージの雛形を作成
  2. パッケージ内にSassをローカルインストール
  3. package.jsonに自作コンパイルコマンドを追加

これに加えて、パッケージ内で、拡張子が.scsssassのファイルはsassフォルダに収納し、それをコンパイルして得られる拡張子が.cssのファイルはcssフォルダに吐き出されるように設定したい。
(これはcompassプロジェクトとして作成した雛形を少し書き換えてそれをnpmパッケージとして登録すれば容易に実現できるが、compassを使わない方法も紹介する。)

また、CSSベンダープレフィックス(ブラウザごとの表示の差異を埋めるための追加コード)を自動で書き加えるためのツールを導入した方が良い。

これらの作業を、新たなディレクトリでSassを書くたびに行うのか?

…それは面倒くさすぎるので、自動化ツールを作りました。

Sassを使う環境(npmパッケージ)作成の自動化

初期設定

下のMySassCreate.shMyConfig.rbを同じディレクトリにコピーしてね。

参考までに、私はホームディレクト/Users/tomixyMyShellScriptというフォルダを作って、その中にMySassCreate.shとMyConfig.rbを置いている。
置き場所に応じて、以降登場する/Users/tomixy/MyShellScript/をそのディレクトリ名に書き換えてね。

macの方はchmod u+x /Users/tomixy/MyShellScript/MySassCreate.shを実行するのを忘れずに。これを実行しないとMySassCreate.shは動きません。

実行方法

  1. 黒い画面を開く
  2. Windowsならbashコマンドでbashを起動
  3. パッケージ(作業ディレクトリ)を作りたい場所にcdコマンドで移動
  4. /Users/tomixy/MyShellScript/MySassCreate.sh パッケージ名を実行

すると、次のようなフォルダが生成される。

f:id:nix_campane:20210322104246p:plain
例として、パッケージ名はsampleとした。

自動化シェルスクリプトMySassCreate.sh全文

zshでしか動作確認していないが、bashでも使えるはず。(というかそもそもbashのためのコード)
windowsの方は…そうだなあ。私はwindows時代、この記事を見ながらbashを導入した気がする。

あ、そうだ忘れてた…jqをインストールしておかないと動かないので注意。
macならsudo brew install jqでインストールできるけど…OSによって違うのでjq インストール OS名と検索。

MySassCreate.sh

#!/bin/sh

PROJECT=$1

compass create $PROJECT # compassを使わない場合はコメントアウト
# mkdir $PROJECT # compassを使わない場合はコメントイン
cd $PROJECT 
# mkdir sass # compassを使わない場合はコメントイン
mkdir css

# compassを使わない場合は下の5行をコメントアウト
cd stylesheets
mv *.css ../css
cd ..
rm -d stylesheets
cp -f /Users/tomixy/MyShellScript/MyConfig.rb config.rb

npm init -y
npm install sass fibers --save-dev
npm install postcss postcss-cli autoprefixer --save-dev 

cat package.json|jq '.scripts += {"start": "sass sas$FILENAMEscss:css/$FILENAME.css --style expanded --watch | postcs--useautoprefixer -b \"last 10 versions\" css/$FILENAME.css -css$FILENAME.css "}' > package.txt
cat package.txt > package.json
rm -f package.txt

細かく解説

※ここからしばらくはコードの解説なので、早く実行したい人はここに飛んでね

シェバン

MySassCreate.shの一部

#!/bin/sh

『これはbashスクリプトですよ〜』とPCに宣言する部分。この記述のあるファイル名を黒い画面で入力+Enterすると、PCは自動的にbashでこのスクリプトを実行しようとする。

もしzshで実行したのなら、この部分は『これはbashスクリプトですよ〜、でもあなたはzshみたいね…まあいいわ、うまくやってあげる。』とPCに呼びかける意味合いになる。 Z ShellのWikiより、

zsh/bin/shとして実行したとき、Bourne Shellの振りをするようにできる。

bashBourne ShellzshはZ Shellの略らしいよ。

しかしシェルとはいえ、Power ShellではMySassCreate.shは実行できないと思われる。構文が結構違うらしい。

コマンドライン引数の取得

MySassCreate.shの一部

PROJECT=$1

/Users/tomixy/MyShellScript/MySassCreate.sh パッケージ名としてこのシェルスクリプトを実行するわけだが、このとき与えたパッケージ名$1に格納されている。
この定数を、これからはPROJECTと呼ぶよ〜という意味。

不思議なことに、PROJECT = $1としてはダメらしい。=の左右にスペースを空けてはいけません。

compassプロジェクト(npmパッケージとなるフォルダ)の作成

MySassCreate.shの一部

compass create compass create $PROJECT # compassを使わない場合はコメントアウト
# mkdir $PROJECT # compassを使わない場合はコメントイン

compass create フォルダ名で、指定したフォルダ内をSass作業用に整理してくれる。具体的には、次のような中身になる。

f:id:nix_campane:20210322125512p:plain
compass create sampleの実行例

私も詳しくは知らないが、

ie.css
Internet Exprorer対応のCSSを書くための雛形
print.css
印刷用のCSSを書くための雛形
screen.css
画面表示用の(つまり普通の)CSSを書くための雛形(CSSリセットの宣言つき)
config.rb
compassコマンドでのコンパイル用の設定を書いておくファイル


…らしい。

とはいえ、前述したようにcompassのサポートは既に終了しているので、ここで作られたie.cssを使ったところで最新のものに対応できるかはわからない。

シェルスクリプトでは、#以降は実行されない部分になる。よって、ここには何を書いても良い。
#!だけは例外なので注意。#!で始まるものはシェバンとして解釈されてしまう。

compassを使わない場合は、compass createの前に#を置く(コメントアウトする)ことでcompass createコマンドを無効化にする。 また、その場合はcompassが作るはずだったフォルダを手動で作成しなければならないため、# mkdir $PROJECTの先頭の#を取る(コメントインする)。

言い忘れていたが、シェルスクリプトでは、事前に宣言しておいた変数は$変数名で参照できる。

パッケージ内のフォルダをカスタマイズする

MySassCreate.shの一部

cd $PROJECT 
# mkdir sass # compassを使わない場合はコメントイン
mkdir css

# compassを使わない場合は下の5行をコメントアウト
cd stylesheets
mv *.css ../css
cd ..
rm -d stylesheets

おそらく、今のカレントディレクトリは$PROJECTフォルダを置いた場所(つまり、$PROJECTフォルダの手前のフォルダ)になっていると思うので、cd $PROJECTでパッケージフォルダ内に移動する。

compassを使わなかった場合は、まだsassフォルダもcssフォルダも作成されていないので、mkdirコマンドで作成する。

compassで自動作成した場合は、拡張子が.cssのファイルがstylesheetsフォルダに格納されている。
わかりづらいので、stylesheetsフォルダは削除し、新規に作成したcssフォルダに中身を移すことにする。

cd stylesheets以降はこの移行作業になるので、compassを使わない場合はコメントアウトで無効化した方が良い。

cd stylesheetsでstylesheetsフォルダ内に移動し、中のファイルをcssフォルダ内に移動する。
*ワイルドカードといい、どんな文字列でもよいことを表す。つまり、*.cssは拡張子が.cssのすべてのファイルである。
../cssは、一つ前のディレクトリに戻って(stylesheetsディレクトリから出て)、その後cssディレクトリ内に入った場所を表す。

mv *.css ../css
すべてのcssファイル(*.css)をcssディレクトリ(../css)にmoveする
cd ..
cssディレクトリから出る(一つ前のディレクトリに戻る)
rm -d stylesheets
stylesheetsというディレクトリ(-d)を削除(remove)する


compassコマンドによるコンパイルの設定をする

compass createコマンドによって作られたconfig.rbファイルの中身はデフォルトのものである。 これをカスタマイズしたものをMyConfig.rbとし、これをそっくりそのままconfig.rbにcopyする。

MySassCreate.shの一部

cp -f /Users/tomixy/MyShellScript/MyConfig.rb config.rb

デフォルトのconfig.rb

require 'compass/import-once/activate'

http_path = "/"
css_dir = "stylesheets"
sass_dir = "sass"
images_dir = "images"
javascripts_dir = "javascripts"

compass設定ファイルの雛形のMyConfig.rb

require 'compass/import-once/activate'

# compassコマンドによるコンパイルでもベンダープレフィックスを使用するための設定
require "autoprefixer-rails"
require "csso"
on_stylesheet_saved do |file|
  css = File.read(file)
  File.open(file, "w") do |io|
    io << AutoprefixerRails.process(css, browsers: ["> 1%", "last 2 versions", "ie 10"])
  end
end

http_path = "/"
css_dir = "css" # 新規に作ったcssフォルダにcssファイルが出力されるようにする
sass_dir = "sass"
images_dir = "image"
javascripts_dir = "js"

# その他の設定
output_style = :expanded
relative_assets = true
line_comments = false

ベンダープレフィックスの設定は、このブログから丸ごとコピペした。
その他の設定については、このブログを参考に選択した。

npmパッケージを作成

MySassCreate.shの一部

npm init -y

これで$PROJECTフォルダ内にpackage.jsonファイルやnode_modulesフォルダが作成される。package-look.jsonファイルも作成されているかも。
npm initコマンドを実行すると、途中でパッケージの設定についていろいろと質問されるが、それらをすべてスキップしてデフォルト値を埋め込むために-yオプションをつけている。

Sassコンパイラなどをnpmでローカルインストール

MySassCreate.shの一部

npm install sass fibers --save-dev
npm install postcss postcss-cli autoprefixer --save-dev

npm install パッケージ名
カレントディレクトリにパッケージをローカルインストールする
fibers
よくわからないが、速くインストールするために処理の仕方を変えるオプション
--save-dev
インストールしたパッケージを、package.jsonに依存パッケージ(これがないとこのアプリは動かないよ!というパッケージ)として記述するオプション。
依存パッケージがアップデートすると今まで使えていたコマンドなどが使えなくなり、コードの修正が必要になることもある。依存パッケージをpackage.jsonに書いておくと、npm側でいろいろな管理処理をしてくれるらしい。
PostCSS
CSSを変換するツール
postcss-cli
PostCSSを黒い画面で使えるようにするツール
Autoprefixer
PostCSSによってベンダープレフィックスを追加するツール

package.jsonの修正点

JSONは、簡単にいえば{ key : value }という形で表されたデータの集まりである。

npm init -yコマンドによりデフォルトで作成されるpackage.jsonは、次のようになっている。

デフォルトのpackage.json

{
  "name": "$PROJECT",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

このファイルを自動で次のように書き換えることを目指す。(scriptsインデックスの値に"start":"コンパイルコマンド"を追加した)

修正後のpackage.json(イメージ)

{
  "name": "$PROJECT",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &exit 1",
    "start":"コンパイルコマンド"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

コンパイルとベンダープレフィックス付加を一気に行うコマンドを作成

コンパイルコマンドとだけ示した部分には、次のコードが入る。 ($filenameは、コンパイルコマンド実行時に渡す引数)

sass sass/$FILENAME.scss:css/$FILENAME.css --style expanded --watch | postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css
sassコマンドについて
sass
拡張子が.scss、.sassのファイルをコンパイル(.cssファイルに変換)するコマンド
sass sass/$FILENAME.scss:css/$FILENAME.css
sass コンパイルするファイル:コンパイル後のファイル
--style expanded
コンパイル後のCSSファイルの書式をexpanded(わかりやすいブログはこちら)に設定
--watch
以後、黒い画面を開いている間は保存する度にコンパイルを実行してCSSファイルを更新する
postcssコマンドについて
postcss ファイル名.css
引数として指定したCSSファイルを解析
--use autoprefixer
postcssでautoprefixerを使うオプション
-b "last 10 versions"
10バージョン前のブラウザまで対応
-o ファイル名
指定したファイルに改変後のCSSを出力
シェルスクリプトにおけるパイプ|
コマンドA | コマンドB
コマンドAを実行し、その標準出力をコマンドBの引数としてコマンドBを実行
標準出力
黒い画面に吐き出されたテキストのこと


コマンドAがファイルの中身を黒い画面に表示するというものなら、表示されたファイルの中身をコマンドBで加工するということになる。

ただし、sassコマンドは.cssファイルを作成するだけで、黒い画面には何も表示しない。このままではpostcssの引数は空であり、エラーになってしまうので、postcssにはcss/$FILENAME.cssという引数をわざわざ渡している。

コマンドBにあたる部分である次のコード

postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css

を解体すると、コマンド本体がpostcss、引数がcss/$FILENAME.css、オプションが--use autoprefixer-b \"last 10 versions\"-o css/$FILENAME.cssということになる。

このように、コマンドAが表示系のコマンドではなく、コマンドBに明示的に引数を渡している場合、パイプ|はただ単にコマンドAを実行した後にコマンドBを実行するという意味の記号として使われている。

コマンドを書き加えたjsonテキストを一旦package.txtに吐き出す

MySassCreate.shの一部

cat package.json|jq '.scripts += {"start": "sass sass/$FILENAME.scss:css/$FILENAME.css --style expanded --watch | postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css "}' > package.txt

もっとわかりやすく表すと、

MySassCreate.shの一部

cat package.json | jq '.scripts += {"start": " さっきのコマンド "}' > package.txt
cat ファイル名
ファイルの中身を黒い画面に表示する
表示系コマンド > ファイル
コマンドの結果を黒い画面に表示するのではなく、ファイルに書き出す
jq '処理' JSON形式のファイル
JSON形式のファイルの中身を取得し、指定された処理をして、黒い画面に表示
.KEY
インデックスがKEYである要素{ "KEY" : "value" }
.KEY += { ITEM }
インデックスがKEYである要素{ "KEY" : value }のvalueの部分にITEMを追加して、要素全体を書き換える


jqコマンドの引数は一見存在しないかのように見える。
しかし、catが表示コマンドであるので、catで表示したファイルの中身をそのままjqコマンドに渡していることになる。
引数として渡されたpackage.jsonのデータを、jqコマンドで処理する。

jq '.scripts += {"start": " コンパイルコマンド "}' package.json > package.txtでも.jsonファイルは正しく作成されるが、コンパイルコマンドの実行時になぜかコンパイル不良が頻出するので、没とした。
おそらくテキストをそのままjqで処理させるのではなく、catコマンドでテキストをリスト化してからjqで処理させた方がいいのだろう。
どちらにしてもシェルスクリプトは原因不明の不具合が日常茶飯事らしいので、スマートなコードを目指すよりも経験的にうまくいく方法をとった方がよさそう。

jq '.scripts += {"start": ""sass sass/$FILENAME.scss:css/$FILENAME.css --style expanded --watch | postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css"}'というコマンドによって、インデックスがscriptsである要素は次のように変わる。

BEFORE

"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
  }

AFTER

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start":"sass sass/$FILENAME.scss:css/$FILENAMEcss --style expanded --watch | postcss --useautoprefixer -b \"last 10 versions\" css$FILENAME.css -o css/$FILENAME.css "
    }

そして、上のようにscriptsの値を書き換えたものを、本来なら黒い画面に表示するわけだが、代わりに> packge.txtによってpackage.txtファイルに書き出すことになる。

最初からpackage.jsonに吐き出せばいいのでは?と思うかもしれないが、そうするとpackage.jsonの中身は空になってしまう。この記事に書かれてあるように、直接package.jsonに上書きするのは原理的に不可能なようだ。

package.txtの中身

{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "sass sass/$FILENAME.scss:css/$FILENAME.css --style expanded --watch | postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css "
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^10.2.5",
    "fibers": "^5.0.0",
    "postcss": "^8.2.8",
    "postcss-cli": "^8.3.1",
    "sass": "^1.32.8"}
  }
}

package.txtの中身をpackage.jsonにコピーする

MySassCreate.shの一部

cat package.txt > package.json
rm -f package.txt

cat package.txt > package.jsonによって、package.txtの中身を黒い画面に表示する代わりに、package.jsonに吐き出す。 このとき、元々のpackage.jsonの内容は消去され、完全に上書きされる。

一時的なデータ保管用であったpackage.txtはもう不要なので、rm -f package.txtで削除する。 『削除していいのですか?』的な確認メッセージが出ると、それに回答する手間が生じるので、確認メッセージを表示しないために-fオプションをつけておく。

作成した自動化ツールの使い方

初期設定が済んでいることを前提で話を進めます。

あと、VScodeユーザーならこの章は読むだけ無駄です。ここに進むことをおすすめします。

SassやCSSを作成するフォルダの作成

実行方法に書かれてある通りなので略。

Sassを書く

さっき作ったフォルダの中の、sassフォルダの中にオリジナルの.scssファイル(または.sassファイル)を追加していってね

Sassのコンパイル

  1. cdコマンドでsassファイルの中へ移動
  2. FILENAME=コンパイルしたいファイル名 npm run startコマンドを実行

startというのがpackage.jsonで定義したコンパイルコマンドだが、このコマンドに直接引数を渡すことは不可能なので、FILENAMEという定数を事前に定義して、それをコマンド内で参照する手段をとっている。

cssフォルダを覗いてみると、コンパイルしたかったファイルと同名の.cssファイル(と.css.mapファイル)が作成されているはず。ベンダープレフィックスも自動で追加されています!!

なお、このコマンドの実行以降は、sassファイルをいじって再保存したり、新たなsassファイルを作って保存したりすると、勝手にコンパイルされてcssフォルダ内が更新されていくよ。黒い画面を閉じない限りね!!

…って、これだとまだ面倒臭いじゃん

…と思いませんでした?

VScodeユーザーなら、ワンクリックでできるようになります!!

VScodeで簡単にパッケージ作成&Sassコンパイルできるようにする

初期設定

task.jsonを開く

  1. shift ctrl Pmacならshift(⬆️) command P
  2. taskと入力
  3. ユーザータスクを開くをクリック

開かれたtask.jsonに次の内容をコピペ

task.json

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Sass new project create",
            "type": "shell",
            "command": "/Users/tomixy/MyShellScript/MySassCreate.sh",
            "args": ["${input:SassProjectName}"],
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "label": "Sass compile & watch start",
            "type": "shell",
            "command": "cd ${fileDirname} && cd .. && FILENAME=${fileBasenameNoExtension} npm run start",
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ],
    "inputs": [
        {
            "id": "SassProjectName", // ${input:***}で指定したID
            "description": "Sass new project name:", // 入力説明文
            "default": "sample", // デフォルト入力値
            "type": "promptString" // 入力タイプ
        }
    ],
}

使い方

SassやCSSを作成するフォルダの作成

  1. shift ctrl Bmacならshift(⬆️) command B
  2. Sass new project createをクリック
  3. 作成したいフォルダ名を入力(デフォルトではsample)

Sassを書く

さっき作ったフォルダの中の、sassフォルダの中にオリジナルの.scssファイル(または.sassファイル)を追加していってね

Sassのコンパイル

  1. shift ctrl Bmacならshift(⬆️) command B
  2. Sass compile & watch startをクリック

cssフォルダを覗いてみると、コンパイルしたかったファイルと同名の.cssファイル(と.css.mapファイル)が作成されているはず。ベンダープレフィックスも自動で追加されています!!

これ以降はsassファイルをいじって再保存したり、新たなsassファイルを作って保存したりすると、勝手にコンパイルされてcssフォルダ内が更新されていくよ。

あとがき

この自動化を実現するために初めてきちんとシェルスクリプトを勉強したので、ほぼほぼシェルスクリプト文法のアウトプットブログになってしまった。

実は、ブログに載せるために何度もテストしていく中で、MySassCreate.shに重大な欠陥があることに気がついた。もちろん修正済みのものを掲載している。ブログにまとめること自体がデバッグ作業。 それにしても、その欠陥というものは他の言語であれば即エラーを吐き出すようなヤバいものだった。あんなコードで動いてしまうシェルスクリプトって怖い。

実を言うとSassの勉強はまだしていないので、これからいろいろコンパイルしていく中でエラーが出る可能性も…そうしたらまたこの記事を修正しよう。安定して動作できることがある程度確認できたらGitHubにも載せる。

task.jsonの書き方についてもいつか追記するかも。とりあえず疲れたからこれでおしまい。

pyファイルの実行を極限まで楽にする【Python用のcode runnerショートカット改造】

code runnerを使えば、pyファイルもCtrl + Alt + Nで瞬時に実行できる。…が、その前にcdコマンドなどで実行したいファイルのあるディレクトリまで移動しておかなければならない。

いちいち手動で移動するのは面倒くさいので、Ctrl + Alt + Nショートカットにディレクトリ移動も組み込んでしまおう、というお話。

前提とする環境

  • pythonコマンドが使える
  • code runnerをインストール済み

ショートカット作成方法

setting.jsonを開き、"code-runner.executorMap":{}内の"python": "なんちゃら"

"python": "cd $dirWithoutTrailingSlash ; python $fileName"

に変更する。(beforeafter)

環境によってはpythonじゃなくてpython3かも。 PowerShell等でpythonもしくはpython3と入力+Enterしてみて、エラーにならずにPythonのバージョン情報が表示された方を当てはめて。

簡単に解説

実行したい(今VScodeで開いている)pyファイルのフルパスがkonofolderniaruyo/jikkositai.pyだとすると、

  • $dir ...konofolderniaruyo/
  • $dirWithoutTrailingSlash ...konofolderniaruyo
  • $fileName ...jikkositai.py

として置き換えられる。

つまり、cdコマンドでkonofolderniaruyoディレクトリに移動した後に、pythonコマンドでjikkositai.pyを実行するということ。

移動と実行という2つの操作を続けて行うことを;で表している。(&&-andだとなぜかエラーが出た)

csファイルだってcode runnerで一発コンパイルしたい!【C#用のcode runnerショートカット】

本来、code runnerはCtrl + Alt + Nでコンパイル・実行できることが最大のメリットなわけだが、どうやらC#ではそうもいかないらしく。 code runnerの初期設定では、CSscriptをインストールしておけばcsxファイルならCtrl + Alt + Nで実行できるとかなんとか。 どちらにせよ、csファイル(というかcsprojファイル)をビルド・実行するには、cdコマンドでビルドしたいcsprojファイルがあるフォルダーに移動した後に、dotnet runコマンドを手打ちする必要がある。

いちいちPowerShellcd ビルドしたいcsprojがある階層のフルパス + dotnet run と打ち込んでビルドするのは面倒臭いので、ショートカットを作成してしまおうというお話。

前提とする環境

  • dotnet runコマンドが使える
  • code runnerをインストール済み

ショートカット作成方法

setting.jsonを開き、"code-runner.executorMap":{}内の"csharp": "scriptcs""csharp": "cd $dir && dotnet run" に変更する。(beforeafter)

すると、Ctrl + Alt + Nで今開いているcsファイルのビルドができるようになった。

よくわからないが、

という2つの操作を続けて行うことを&&で表す

という意味合いっぽい。

効率化された試し割りによる素数判定【細かすぎるコード解説:C言語編】


14622回の除算で1000以下の素数を求める

手がかり

  •  2 以外の素数はすべて奇数
  •   1以外の正の整数はどれも素数の倍数といえる(素因数分解
  • 素数nで割り切れない整数は、nより大きいnの倍数でも割り切れない

 1 nでしか割り切れない整数 n素数)を探すとき、それより小さい素数で割り切れないものは、その他の整数(素数の倍数)でも割り切れない。

そのため、より小さいすべての素数で割ってみて割り切れるかのみ調べればよい。

プログラムのソースコード【細かすぎる注釈つき】

#include <stdio.h>

int main(void)
{
    //2以上1000以下の整数をnと表すことにする
    //つまり、整数nの中から素数を探すことになる
    int n;

    //除算回数を数えるカウンターを用意
    unsigned long counter=0;/*unsigned long…長い桁数の非負整数を格納できる箱の名称(型)*/

    //素数を入れる箱を500個用意する
    //2以外の素数はすべて奇数であり、1から1000までの数の中に奇数は500個しかない
    //そのうち1は素数ではなく、代わりに2は素数であるから、
    //結局素数を入れる箱は500個で足りる
    int prime[500];

    //i番目の素数をprime[i]と表すことにする
    int i;

    //既に見つけた素数の個数をptrとする。現時点ではまだ0である
    int ptr=0;

    //2と3は素数である
    prime[ptr++]=2;/*prime[0]=2と記憶した後に、ptrの値を1つ増やす(見つけた素数の個数が1になる)*/
    prime[ptr++]=3;/*prime[1]=3と記憶した後に、ptrの値を1つ増やす(見つけた素数の個数が2になる)*/

    //このように、小さい数から順に素数を探していくから、
    //番号が若い素数の方が小さい素数である

    //現時点で見つかっている素数2個(prt=2)のうち最大のものはprime[1]=3であるように、
    //これまで見つけたptr個の素数のうち最大のものは、prime[ptr-1]で表される

    //5以上1000以下の数の中から素数を探す
    for (n=5 ; n <= 1000; n+=2)/*5から始まって2ずつ増やしていくことで、奇数のみが対象になる*/
    {
        //これまで見つけた素数prime[0]~prime[ptr-1]すべてで割ってみる
        //しかし、これから見つける素数はすべて奇数であるので、2で割り切れる数(偶数)は最初から除外してよい
        //よってprime[0]である2で割る必要はないので、3=prime[1]~prime[ptr-1]で割ってみる
        for ( i = 1; i < ptr; i++)
        {
            counter++;/*除算回数が1増える*/

            if (n % prime[i] ==0)/*もし整数n(>4)がそれより小さい素数で割り切れたなら*/
            {
                break;           /*nは素数ではないので、もう他の数で割る必要はない⇒このforから追放*/
            }

            //ここでi++が実行され、iの値が1増える

            //割り切れなかったものはこのforの冒頭に戻り、iが1大きな値に書き換えられたforの中身を繰り返す
            //                                       (つまりより大きい素数で割られる)

        }
        
        //途中でforを追放されたものはここに到達している
        //まだiの値がptrよりはるかに小さい段階で中断されているので、
        //ptr=iという条件を満たさず、if(ptr==1){}はスルーしてこのまま外側のforからも抜けることになる

        //最大素数prime[ptr-1]までのすべての素数で割り切れなかったものは、
        //最後までbreakで抜けることなく、後処理i++を受けてここに到達する
        //つまり、最大素数での最後の除算をする段階ではi=ptr-1だが、その後のi++によって今はi=ptrとなっている
        //これは次のif文も実行されることになる

        if (ptr == i)/*i=ptrなら(これまで見つけたprime[ptr-1]までのすべての素数で割り切れなかったら)*/
        {
            prime[ptr++]=n;/*そんな整数nを新たな素数prime[ptr]として登録する
                            *(登録した後に、登録済み素数の数が1増える)       */
        }

        //ここでn+=2が実行され、nの値が2増える
        //外部forの冒頭に戻り、2大きな整数nについて全体の処理が再度行われる
        //このようにして、1000以下の整数をすべて登録済み素数で割って、選別する
        
    }

    //1000以下の整数すべての選別が終わると、ここに到達する
    //最終的に登録された素数すべて(prime[1]~prime[ptr-1])を一覧で表示する
    for ( i = 0; i < ptr; i++)
    {
        printf("%d\n",prime[i]);
    }
    
    //除算回数を表示する
    printf("乗除を行った回数:%lu\n",counter);

    return (0);
 }

3774回の乗算・除算で1000以下の素数を求める

強力な武器

改良版プログラムのソースコード【細かすぎる注釈つき】

変更した箇所にのみ補足説明を加えている。

#include <stdio.h>

int main(void)
{
    int n;

    //乗算・除算回数を数えるカウンターを用意
    unsigned long counter=0;

    int prime[500];

    int i;

    int ptr=0;

    prime[ptr++]=2;
    prime[ptr++]=3;

    for (n=5 ; n <= 1000; n+=2)
    {
        //2つの状態のどちらか(ONかOFFか)を判定するために使う変数をフラグという
        //今回は割り切れたか否かを判定する用に使う
        int flag = 0;/*初期値は0(フラグを下ろしておく)*/

        //nの平方根以下のすべての素数で割ってみる
        //『素数pがnの平方根以下』という条件は、両辺2乗して『pの2乗がn以下』と言い換えられる
        for ( i = 1; counter++ , prime[i]*prime[i] <= n; i++)
                     /*《A,B …AとBを順に実行し、Bの値を返す》
                      *for内部を実行するかの判定をするのはprime[i]*prime[i] <= nだが、
                      *判定の度に乗算*をカウントするということ             */
        {
            counter++;

            if (n % prime[i] ==0)/*割り切れたなら*/
            {
                flag = 1;        /*フラグを上げる*/
                break;           
            }

        }

        if (!flag)         /*flag=0(フラグが下がったまま)なら*/
        {
            prime[ptr++]=n;/*割り切れなかったということなので、素数として登録*/
        }
        
    }

    for ( i = 0; i < ptr; i++)
    {
        printf("%d\n",prime[i]);
    }
    
    printf("乗除を行った回数:%lu\n",counter);

    return (0);
 }

コード引用元

今回掲載したコードのベースとなっているのは、柴田望洋先生の著書明解C言語入門編の109・111ページに掲載されているサンプルコードです。 説明の都合上、変数の名称や変数宣言の順序を変えています。また、括弧のレイアウトは自分好みに変えています。

定理の証明に関する参考文献

現在LaTeXで制作中の整数論ノートに今回素数判定に用いた定理の証明も掲載予定です。 厳密な証明ではないですが、コード引用元の書籍では正方形の図によってわかりやすく導出されています。 厳密な証明を追いかけたい方にはモノグラフ 整数をオススメします(が、絶版なんだよなあ…)。

LaTeXで使える付箋風の枠【tcolorboxの可能性】

tcolorboxのマニュアルの8.3節にある作例にちょっとだけ手を加えたら、思いがけず可愛らしい付箋のような枠が生まれたので記録しておく。

コード全文

\usepackage[dvipdfmx]{graphicx,color}%オプションは一例
\usepackage{xcolor}

\usepackage{tikz}
\usetikzlibrary{calc}%座標を使って図形を描くために必要

\usepackage{xparse}%オプション(省略可能引数)をもつコマンド作成

\usepackage{tcolorbox}
\tcbuselibrary{listings,breakable,xparse,skins,hooks}
 %listings…私の環境ではbreakableを使う際に必要
 %breakable…ページまたぎ可能な枠を作成できる
 %xparse…オプションをもつ枠を作成できる
 %skins…TikZで枠のデザインを描き足せる
 %hooks…多種多様な機能が含まれるため、とりあえず読み込んでおくと安全
 %           たとえばunderlay unbrokenに必要
 
%付箋環境~水色バージョン~の定義
\DeclareTColorBox{fusenmz}{m O{} }%
{enhanced,
 colframe=white,
 colback=yellow!10!white,
 coltitle=cyan!40!black, 
 fonttitle=\bfseries,breakable,
 underlay unbroken={\begin{tcbclipinterior}
                             \shade[inner color=cyan!80!yellow,outer color=yellow!10!white] (interior.north east) circle (2cm);
                             \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                           \end{tcbclipinterior}}, 
 underlay first={\begin{tcbclipinterior}
                       \shade[inner color=cyan!80!yellow,outer color=yellow!10!white] (interior.north west) circle (2.5cm);
                       \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                    \end{tcbclipinterior}}, 
 underlay last={\begin{tcbclipinterior}
                       \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                    \end{tcbclipinterior}}, 
 title={#1},
 attach title to upper=\quad, #2
}

%付箋環境~桃色バージョン~の定義
\DeclareTColorBox{fusenmm}{m O{} }%
{enhanced,
 colframe=white,
 colback=yellow!10!white,
 coltitle=magenta!40!black, 
 fonttitle=\bfseries,
 breakable,
 underlay unbroken={\begin{tcbclipinterior}
                             \shade[inner color=magenta!80!yellow,outer color=yellow!10!white] (interior.north east) circle (2cm);
                             \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                          \end{tcbclipinterior}}, 
 underlay first={\begin{tcbclipinterior}
                       \shade[inner color=magenta!80!yellow,outer color=yellow!10!white] (interior.north west) circle (2.5cm);
                       \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                    \end{tcbclipinterior}}, 
 underlay last={\begin{tcbclipinterior}
                       \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                    \end{tcbclipinterior}}, 
 title={#1},
 attach title to upper=\quad, 
 #2
}

使用法

%fusenmzの場合も同様
\begin{fusenmm}{タイトル}[さらなるtcolorboxのオプション]
テキスト
\end{fusenmm}

使用例ギャラリー

%プリアンブルに追加
\usepackage[math]{anttor}%オシャレな数式・英文フォント
\usepackage{enumerate}

%この下は\begin{document}以降

\begin{fusenmm}{My Title}
\begin{enumerate}[(1)]
\item A,A,B,C,Dを1列に並べる並べ方は何通りあるか。
\item A,A,B,B,C,Dを1列に並べる並べ方は何通りあるか。
\end{enumerate}
\end{fusenmm}

\begin{fusenmz}{My Title}
\begin{enumerate}[(1)]
\item A,A,B,C,Dを1列に並べる並べ方は何通りあるか。
\item A,A,B,B,C,Dを1列に並べる並べ方は何通りあるか。
\end{enumerate}
\end{fusenmz}

f:id:nix_campane:20210110144154j:plain

前回紹介したリングノート枠の中で使えば、付箋ノート風になってますます可愛いのでは…?

なお、付箋らしさは損なわれるが、一応ページまたぎも可能である。

ページまたぎ可能なリングノート枠【tcolorboxの可能性】

f:id:nix_campane:20210110131300j:plain

ありそうでなかなかない、LaTeXで使えるリングノート枠。
下のブログを見つけてfancyparに惚れこんだものの、ページまたぎができないと察して頭を抱えていた。

konoyonohana.blog.fc2.com

ならば自分で作ればいいじゃないか!という持ち前の勢いの良さで、tcolorboxのマニュアル(※530ページ、全文英語)を読み始める。
その他にも海外ブログやら類似パッケージのstyファイルやらいろいろなものを読み漁って、なんとか丸1日で実装にこぎ着けたので、コード全文とその解説をまとめておく。

なお、以下ではすべてpLaTeX(ptex2pdf)でコンパイルしている。

手順0,制作の方向性

fancyparは『個々の段落を装飾する』マクロ集であり、複数の段落をまとめて囲むことは想定されていない。実際、fancyparパッケージで定義されているものはコマンドであり、環境ではないので、(\parboxで囲んで無理やり1行と認識させない限り)内部で改行などをすればエラーが吐き出されるはずである。

そこで今回実装したいのは、fancyparの\NotebookParというコマンドで出力されるリングノート枠の改良版だ。
具体的には、次のような機能をもつものを作りたい。

  • 枠内で改行可能
  • ページまたぎ可能
  • 枠内であらゆるコマンドや環境が使える

なお、個人的に罫線は無い方が読みやすい気がするので、本家のような罫線はつけない方向で行く。

手順1,fancyparのstyファイルからリング部分のコードを抜き出す

結論から言うと、fancypar.styの116~124行目がリング部分を記述するコードである。

    \tikz{%
      \draw[draw=black,fill=white] (-1,-0.3) circle (3pt);%リング穴を描画
      \ifFP@fancypar@spiral%spiral=trueというオプションをつけた場合は以下の処理(リングを描画)
        \draw[very thin,rotate=4,double=\FancyNSColor,%
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);%
      \else\relax%spiral=falseというオプションをつけた場合は何もしない
      \fi
    }

今回はspiral=trueとしてリングノート風の出力を得たいので、リング穴とリングを描画するコードだけ抜き出す。

 \tikz{%
      \draw[draw=black,fill=white] (-1,-0.3) circle (3pt);%リング穴を描画
      \draw[very thin,rotate=4,double=\FancyNSColor,%この行以下でリングを描画
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);%
 }

\FancyNSColorという色は、43行目で次のように定義されている。

\DeclareOptionX[FP]<fancypar>{spiralcolor}{\def\FancyNSColor{#1}}

これは、spiralcolor=…というオプションで指定した色が\FancyNSColorであるという意味だが、今回はそのようなオプションはつけずにデフォルトの色を指定することにする。
fancyparパッケージのドキュメント(fancypar.pdf)の6ページを見ると、デフォルトの色はLightYellow3であるらしい。
インターネットでRGB値を調べ、次のように定義しておく。

\definecolor{lightyellowiii}{RGB}{205,205,180}

先ほどの\FancyNSColorをlightyellowiiiに置き換えて、次のようにするとコンパイルが可能になる。

\documentclass[a4paper,12pt,dvipdfmx]{jsarticle}
\usepackage[dvipdfmx]{graphicx,color}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc}
\definecolor{lightyellowiii}{RGB}{205,205,180}

\begin{document}

 \tikz{%
      \draw[draw=black,fill=white] (-1,-0.3) circle (3pt);%リング穴を描画
      \draw[very thin,rotate=4,double=lightyellowiii,%この行以下でリングを描画
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);%
 }
 
\end{document}

コンパイル結果は、次のようになる。

f:id:nix_campane:20210110131158j:plain

手順2,リングを新たなデコレーション単位として定義する

さて、問題はこのリングをどうやって枠の左上から左下までに渡って等間隔に配置するか?なのだが、散々ネットを徘徊した末に、次の方法で実装できそうな予感がしてきた。

TikZにはdecoration.shapesというライブラリがある。
このライブラリを読み込むと、予め定義した図形(猫の足跡とか)を何度もスタンプを押すように並べることができるようになる。
そこで、先ほど描画したリング1つを新たなスタンプとして定義して、枠の左上から左下まで並べていけば、目的のレイアウトは実現できそうだ。

その前に、先ほど描いたリングを90°回転させておく。

\documentclass[a4paper,12pt,dvipdfmx]{jsarticle}
\usepackage[dvipdfmx]{graphicx,color}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc}
\definecolor{lightyellowiii}{RGB}{205,205,180}

\begin{document}

 \tikz{%
      \draw[draw=black,fill=white,rotate=90] (-1,-0.2) circle (3pt);%rotate=90で90°回転、回転させるとリングと穴がズレるので、穴となる円の中心をちょっとずらした
      \draw[very thin,rotate=90,double=lightyellowiii,%rotate=90で90°回転
          double distance=1.5pt]
          (-1,-0.2) arc (40:-250:10pt and 2pt);
 }
 
\end{document}

コンパイル結果は

f:id:nix_campane:20210110131214j:plain

どうやらスタンプとして並べられるときに図形が-90°回転されるようなので、予め90°回転させておかないと目的の出力が得られない。

自分で新たなスタンプを定義するには、\pgfdeclaredecorationコマンドを用いるらしい。
上の画像のリングをspiralスタンプとして、次のように定義する。

\pgfdeclaredecoration{spiral}{initial}
{
 \state{initial}
[width=\pgfdecoratedpathlength/floor(\pgfdecoratedpathlength/13pt] %13がリングの間隔を決める
  {
      \draw[draw=black,fill=white,rotate=90] (-1,-0.2) circle (3pt);%ここからがさっきのコード
      \draw[very thin,rotate=90,double=lightyellowiii,%
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);%ここまでがさっきのコード
  }
  \state{final}
  {
    \pgfpathmoveto{\pgfpointdecoratedpathlast}
  }
}

コードの意味についてはとりあえず省略(実はまだあんまりよくわかっていない)
とりあえず、
13より大きな値にするとリングの間隔はより広くなる。小さな値にするとより狭くなる。ここは好みで調整

実際にこのスタンプを使ってみよう。

 \tikz{
         \draw[decorate,decoration={spiral}]  %spiralスタンプを使う宣言
          (0,0)--(0,-10);% (0,0)と(0,-10)を結ぶ直線状にスタンプを並べる
 }

のようにしてスタンプを並べることができる。
コンパイル用の完全版は、

\documentclass[a4paper,12pt,dvipdfmx]{jsarticle}
\usepackage[dvipdfmx]{graphicx,color}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc,%座標を使って図形を描くために必要
                   decorations.shapes}%スタンプを並べるために必要
\definecolor{lightyellowiii}{RGB}{205,205,180}

\pgfdeclaredecoration{spiral}{initial}%ここからがさっきのspiralスタンプの定義
{
 \state{initial}[width=\pgfdecoratedpathlength/floor(\pgfdecoratedpathlength/13pt)] 
  {
      \draw[draw=black,fill=white,rotate=90] (-1,-0.2) circle (3pt);%
      \draw[very thin,rotate=90,double=lightyellowiii,%
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);
  }
  \state{final}
  {
    \pgfpathmoveto{\pgfpointdecoratedpathlast}
  }
}%ここまでがさっきのspiralスタンプの定義

\begin{document}

 \tikz{
         \draw[decorate,decoration={spiral}]  %spiralスタンプを使う宣言
          (0,0)--(0,-10);% (0,0)と(0,-10)を結ぶ直線状にスタンプを並べる
 }

\end{document}

コンパイル結果は、

f:id:nix_campane:20210110131234j:plain

手順3,デコレーション機能をtcolorboxのデザインで使う

tcolorboxでは、『左上』などの位置情報を方角で表現する。

  • 枠の左上の角…frame.north west
  • 枠内部の左上端…interior.north west

よって、枠の左上から左下にわたってspiralスタンプを並べる命令は次のようにかける。

\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);

(※いい感じにリングノートに見えるように、左端から少しずらしている)

ringnote環境のコード全文

\documentclass[a4paper,12pt,dvipdfmx]{jsarticle}%オプションは一例
\usepackage[dvipdfmx]{graphicx,color}%オプションは一例
\usepackage{xcolor}

\usepackage{tikz}
\usetikzlibrary{calc,%座標を使って図形を描くために必要
                   decorations.shapes}%スタンプを並べるために必要

\usepackage{xparse}%オプション(省略可能引数)をもつコマンド作成

\usepackage{tcolorbox}
\tcbuselibrary{listings,breakable,xparse,skins,hooks}
 %listings…私の環境ではbreakableを使う際に必要
 %breakable…ページまたぎ可能な枠を作成できる
 %xparse…オプションをもつ枠を作成できる
 %skins…TikZで枠のデザインを描き足せる
 %hooks…多種多様な機能が含まれるため、とりあえず読み込んでおくと安全
 %           たとえばunderlay unbrokenに必要
 
%リング色の定義
\definecolor{lightyellowiii}{RGB}{205,205,180}

%spiralスタンプの定義
\pgfdeclaredecoration{spiral}{initial}
{
 \state{initial}[width=\pgfdecoratedpathlength/floor(\pgfdecoratedpathlength/13pt)] 
  {
      \draw[draw=black,fill=white,rotate=90] (-1,-0.2) circle (3pt);%
      \draw[very thin,rotate=90,double=lightyellowiii,%
          double distance=1.5pt]%
          (-1,-0.2) arc (40:-250:10pt and 2pt);
  }
  \state{final}
  {
    \pgfpathmoveto{\pgfpointdecoratedpathlast}
  }
}

%リングノート枠の定義(tcolorbox)
\DeclareTColorBox{ringnote} 
                                    { O{} O{white} O{} }%Oはオプション引数(省略可能)であることを表す。#1,#3は省略したら何もしない、#2は省略したらwhiteになる
{ enhanced,%必須
  colback=#2,%枠内の背景色を#2にする
  breakable,%ページまたぎ可能にする
  sharp corners,%枠の角を尖らせる
  left*=10mm,%枠の左辺から枠内のテキストまでの余白を調整
  boxrule=0.4pt,%枠の囲み線の太さを0.4ptにする
  %ここまでで枠を描く↑↑↑
  %ここから枠にリングを書き足す↓↓↓(underlay…枠の上にTikZで描画する)
  underlay unbroken={\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);},%ページをまたがないときの枠のデザイン
  underlay first={\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);},%ページをまたぐときの最初のページの枠のデザイン
  underlay middle={\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);},%ページをまたぐときの途中のページの枠のデザイン
  underlay last={\draw[decorate,decoration={spiral}]  ($(interior.north west)+(1.375,0)$)--($(interior.south west)+(1.375,0)$);},%ページをまたぐときの最後のページの枠のデザイン
  %ここからはオプションの定義↓↓↓
  IfValueTF={#1}%#1があるかないかによって次のように処理が異なる
                {title=#1}%#1があるときは、#1をtitleとする(title枠が描かれる)
                {},%#1がないときは、title枠なし
  #3%#3があるときは、#3を枠のデザインとして追加する
}

ringnote環境の使い方

\begin{ringnote}[タイトル][テキスト背景色][さらなるtcolorboxオプション]
テキスト
\end{ringnote} 

使用例ギャラリー(ページをまたがない例)

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}%タイトル枠なし
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131300j:plain

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[title]%タイトル枠あり
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131310j:plain

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[title][green!7]%タイトル枠あり、枠内テキスト背景色green!7
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131330j:plain

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[][green!7]%タイトル枠なし、枠内テキスト背景色green!7
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131343j:plain

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[title][green!7][colbacktitle=blue!5,%タイトル枠背景色blue!5
                                       colframe=white,%枠の色white
                                       coltitle=blue!50!black]%タイトルの文字色blue!50!black
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131352j:plain

\usepackage{lipsum}%ダミーテキスト
\definecolor{powderblue}{RGB}{230,230,255}%色パウダーブルーの定義
\usepackage{frcursive}%フランス語筆記体フォント(タイトルに使用)
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[\bfseries\textcursive{title}][powderblue!50!white][colframe=white,%枠の色white
                                                                    title style={fill,left color=red!20!white,right color=blue!20!white},%タイトル枠背景を左側red!20!white・右側blue!20!whiteのグラデーションに
                                                                    coltitle=cyan!50!white]%タイトルの文字色cyan!50!white
\lipsum[1]
\end{ringnote}

f:id:nix_campane:20210110131403j:plain

使用例ギャラリー(ページをまたぐ例)

\usepackage{lipsum}%ダミーテキスト
%ここまでをプリアンブルに追加↑↑↑
%ここからは\begin{document}以降

\begin{ringnote}[title]
\lipsum[1-9]
\end{ringnote}


f:id:nix_campane:20210110131426j:plain
f:id:nix_campane:20210110131430j:plain
f:id:nix_campane:20210110131422j:plain

Dimention too large対策【minipage環境でTeXを騙せ】

xymatrixを使用していると、しょっちゅうdimention too largeエラー地獄に陥る。
最終的なエラーメッセージの少し上には、
Overfull \vbox (数字pt too high) has occurred while \output is active
という記述がある。
数字の部分は場合によって異なるらしく、10未満であれば

\setlength\headheight{10pt}

をプリアンブルに加えることで改善するらしい。
私が直面したエラーでは約15000だったため、ダメもとで\setlength\headheight{16000pt}と書き加えてみたが、まあそりゃ無理である。
ちなみに\setlength\headheight{16000pt}と加えてタイプセットしたときに出たエラーは
! Huge page cannot be shipped out.(直訳:巨大なページは出荷できません。)
…そりゃそうよね。
そんなわけで別な解決策を探した結果、次のようにしたらうまくいった。

❂ ❃ ❅ ❆ ❈ ❉ ❊ ❋ ❂ ❃ ❅ ❆ ❈ ❉ ❊ ❋
まず、\end{document}を少し上の行に移動させて、\end{document}より下にテキストがある状態でタイプセットしてみる。
正常にコンパイルされるまで、\end{document}を少し上に移動→タイプセットを繰り返す。(dimension too large以外のエラーは無視して続行)
正常にコンパイルされるときが来たら、そのときの\end{document}の直後にある部分がエラーの原因である。

エラー箇所を特定できたら、

\begin{minipage}[t]{40zw}
エラー部分(とその前後、1ページに収まる長さで)
\end{minipage}

とエラー部分を囲んで、\end{document}を一番下の行に戻してタイプセットする。

❂ ❃ ❅ ❆ ❈ ❉ ❊ ❋ ❂ ❃ ❅ ❆ ❈ ❉ ❊ ❋

難しい話はよくわからないが、この方法はエラー部分を含む段落を巨大な1文字と認識させることで、エラー部分に気づかせないようにする手法らしいな(素人の信用ならない意訳)
40zwは、その巨大な1文字の横幅である。1zwは平仮名1文字の横幅で、デフォルトでは1行に40文字並ぶため、40zwと設定した。この値を小さくすれば、ページの右端に着く前に改行されることになる。
tはtopの略で、この巨大な1文字を\begin{minipage}の直前の行のすぐ次の行に配置することを意味する。cにすれば余白の真ん中の行、bにすればページの一番下の行に沿って配置されることになるのだろう。つまり、cやbにすれば直前の行との余白が空く。普通に横書きで上の行から順に書いている状態なら、tにしておけば自然な見栄えになるはずだ。

参考にしたウェブサイトはこちら。このブログは精一杯意訳した結果なので、説明不足・解釈違いは本家を見て補ってほしい。
7.6 ボックス