Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] mcpp を使用してCプリプロセッサで無効化された箇所の色分け機能を強化 #1084

Closed
wants to merge 9 commits into from

Conversation

beru
Copy link
Contributor

@beru beru commented Nov 2, 2019

PR の目的

Cプリプロセッサで無効化された箇所を色分けして表示する機能を強化するのが目的です。

カテゴリ

  • 機能追加
  • 仕様変更

PR の背景

C/C++タイプ別設定のカラーのコメントスタイルのブロック型に #if 0#endif の指定が存在します。しかしこの簡易的な機能ではCプリプロセッサで無効化された箇所の色分けが正確に行えない場合があります。

C/C++言語のソースコードをサクラエディタで開いて閲覧したり編集する際に、色分けが不正確だとどの部分のコードが有効化/無効化されているのかを把握するのが大変なので改善を行いたいです。

PR のメリット

プリプロセッサの色分け表示が以前より正確になります。

PR のデメリット (トレードオフとかあれば)

  • mcpp というライブラリをプロジェクトに取り込む形になっている
    • スタティックリンクではなく、正規表現ライブラリと同様にDLLとして利用するようにした方が良いかもしれません。
    • 明示的なリンクを行うようにしてファイルが存在する場合だけ機能を使えるようにするようにした方が本体側のプロジェクトを肥大化せずに済みそうです。
    • mcpp の公式な開発プロジェクトはもうアクティブにメンテされていないようです。fork されたプロジェクトはgithub に色々存在しています。
    • mcpp にはメモリリークする不具合があります。繰り返し呼び出す使い方を想定していなかったのかもしれません。
      • 見つけた箇所については対策を入れました。
  • Cプリプロセッサの色分けを有効にしていると、レイアウト処理の度にファイル全体を一時ファイルに書き出して mcpp の処理を呼び出すので負荷が大きい
    • ファイル経由ではなくメモリ経由にした方がドライブに対する負荷は少ないはずですが、mcpp 側の入力がファイルな事もあり、やっつけ実装にしています。
    • ソースコード編集時に操作に応じた必要最小限のプリプロセス処理を行うべきですが、このPRの実装ではファイル全体を毎回処理しています。大きいファイルの編集を行う際に問題になるかもしれません。
  • F5 キーを押して表示を更新したり、Ctrl + マウスホイール やファイル保存操作等を行わないと、表示が正しく更新されない
  • 統合開発環境ほどには色分けが正確でない
    • より正確にするにはコンパイラに指定するインクルードディレクトリ(-Ihoge)やインクルードファイル(-??)や#defineの指定(-Dhoge)を再現する必要があります。統合開発環境ではなくテキストエディタで単一のファイルを編集する用途ではそこまでやらなくても良いかなと考えています(実装が大変そうだし…)。
    • ソースコードのディレクトリを -I で指定して mcpp を実行しているので、相対パスの #include は働きます。
    • 一時ディレクトリに書き出している為にそこからの相対パスでも #include が動くので、一時ディレクトリに #include するファイルと同名のファイルが存在した場合にそのファイルを取り込んでしまうかも
  • グローバル変数 g_CColorStrategy_nCurLine を追加しており、実装方法が汚い
    • 引数を追加したりするのが大変なのでやっつけな対処になっています。
  • MinGW ビルドに対応してない

PR の影響範囲

タイプ別設定のカラーの色指定リストの一番末尾に Cプリプロセッサ の項目が追加されます。

image

プリプロセッサで無効化された箇所の色を指定する事が出来ます。
プリプロセッサで無効化されていない箇所の色については指定出来ません。

レイアウト処理

PR のデメリットに色々と記載しましたが、Cプリプロセッサを色分け表示する設定にすると、レイアウト処理の度に現在編集している文書の内容を一時ファイルに書き出し mcpp ライブラリを呼び出しています。

関連チケット

#413

参考資料

http://mcpp.sourceforge.net/index-jp.html
https://www.ipa.go.jp/files/000005716.pdf

@AppVeyorBot
Copy link

Build sakura 1.0.2364 completed (commit bfc6cfca64 by @)

@berryzplus
Copy link
Contributor

👍 なんですが、マージして「お試し」するには重い変更なのかな?という感じです。

サクラエディタには自前で構文解析を行う機構(アウトライン解析だったかな?)があるので、そこを強化する or 代替実装を提供するというカタチにすると実現しやすいかもです。

experimental ブランチの作成をマジメに考えた方がいいのかも。

@beru
Copy link
Contributor Author

beru commented Nov 2, 2019

👍 なんですが、マージして「お試し」するには重い変更なのかな?という感じです。

サクラエディタには自前で構文解析を行う機構(アウトライン解析だったかな?)があるので、そこを強化する or 代替実装を提供するというカタチにすると実現しやすいかもです。

experimental ブランチの作成をマジメに考えた方がいいのかも。

mcpp を https://github.com/sakura-editor 以下のリポジトリとして追加しても構わなければ、そこに改造版を入れたいです。sakura 本体のリポジトリに mcpp を入れてしまうのはやはり良くないかもしれないですね、mcpp のライセンスは BSD ライセンスで、sakura 側は zlib ライセンスなので、混ぜるとなんかドキュメントの記載等がややこしそうだし…。

アウトライン解析は実行タイミングが限定されているので同じ事の実現は今のままでは無理じゃないかと思います。今回の変更は mcpp 側のコードを少し変更して無効行のフラグをメモリに書き出すようにして、サクラエディタ側の色切り替え処理のバリエーションを追加して対応しています。

本体の字句・構文解析を強化したいとも思うんですがなかなか簡単にはいかなそうです。が、それをやらないと実現出来ない事も色々ありますね。

カーソルが括弧の上にいる時に Ctrl + ] キーを押すと対応する括弧の位置に移動しますが、#ifdef 等のプリプロセッサでも同じように位置を切り替えられたら良いなと思ってます。Visual Studio のエディタだとそれが出来ます。

@beru
Copy link
Contributor Author

beru commented Nov 3, 2019

メモリをファイルとして扱う方法を調べてみました。

https://stackoverflow.com/a/50087392/4699324

CreateFile する際に FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE を指定する事でなるべくドライブに書かれないようになるみたいです。

@AppVeyorBot
Copy link

Build sakura 1.0.2365 completed (commit f93e9cf0e0 by @beru)

@beru
Copy link
Contributor Author

beru commented Nov 3, 2019

メモリをファイルとして扱う方法を調べてみました。

https://stackoverflow.com/a/50087392/4699324

CreateFile する際に FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE を指定する事でなるべくドライブに書かれないようになるみたいです。

FILE_FLAG_DELETE_ON_CLOSE を指定してファイル作成すると他から読み取りが出来ないので、作成したハンドルを元に処理していくしかないようです。。少し厄介。。

@berryzplus
Copy link
Contributor

リポジトリの話 => issue 立ててきました。

アウトライン解析は実行タイミングが限定されているので同じ事の実現は今のままでは無理じゃないかと思います。今回の変更は mcpp 側のコードを少し変更して無効行のフラグをメモリに書き出すようにして、サクラエディタ側の色切り替え処理のバリエーションを追加して対応しています。

  • アウトライン解析の実行タイミングが正しくない(かもしれない)というのは思ってました。
  • 結果的に「どうしたらいい(と思う)」かが、このPRに入ってる感じだと思います。
  • サクラエディタ本体に統合するうえでは「無効行のフラグ」の扱いをどうするか?が課題なんじゃないかと思っています。現状だと CDocLine にフラグ用のメンバを追加したりしないといけなくて、アクセス用の専用クラスも用意する必要があります。まー、もうちょいあとの話になる感じ。

カーソルが括弧の上にいる時に Ctrl + ] キーを押すと対応する括弧の位置に移動しますが、#ifdef 等のプリプロセッサでも同じように位置を切り替えられたら良いなと思ってます。Visual Studio のエディタだとそれが出来ます。

#ifdef に関しては「折り畳み機能」の要望が昔からある気がします。
折り畳み実現のためにも、なんとか本体側に解析したデータ構造を渡したいです。

メモリをファイルとして扱う方法を調べてみました。

小ネタ・・・
windows的には、メモリ≒仮想メモリ≒メモリマップトファイルなので、
乱暴にいってしまえば「メモリ≒ファイル」です。

プログラマが「メモリ」と認識するものは、「物理メモリにマップされた仮想メモリ」という「仮想メモリ」を特殊化した概念です。仮想メモリの作成時に具体的な「マップされるファイルのファイルハンドル」を指定しないと、windowsが「閉じるとき削除する一時ファイル」を作成します。なので、プログラマが「メモリ」と認識するものの実体は、実はファイルです。。。

この辺は boost の inter process communication 周辺が参考になると思います。

@berryzplus
Copy link
Contributor

FILE_FLAG_DELETE_ON_CLOSE を指定してファイル作成すると他から読み取りが出来ないので、作成したハンドルを元に処理していくしかないようです。。少し厄介。。

何を試みてるかが分かれば打開策を提案できるかも・・・。

@beru
Copy link
Contributor Author

beru commented Nov 3, 2019

リポジトリの話 => issue 立ててきました。

下記のIssueの作成ありがとうございます。
sakura-editor/management-forum#76

* アウトライン解析の実行タイミングが正しくない(かもしれない)というのは思ってました。

アウトライン解析の実装って CViewCommander::Command_FUNCLIST が呼び出されてそこからアウトライン解析の種別の enum 値に応じた switch 文で CDocOutline::MakeFuncList_HogeHoge 等の呼び出しを行っています。

最初はC言語か何かの関数名一覧をリストアップする実装だったんですかね?今は色々な種類の文書に対してのアウトライン解析処理が個別に入ってますね。

実行タイミングが正しい正しくない、については元々のデザインというか仕様ではそのタイミングで行うって決めた事なので、正解というのは無いかもしれません。

* 結果的に「どうしたらいい(と思う)」かが、このPRに入ってる感じだと思います。

レイアウト処理で色分け処理が呼び出されてそこでも各種の字句解析は行われていますが、テキストエディタ用のある程度単純な処理が主だと思います。このPRではそこの仕組みを無理やり使っているようなやり方で実装してます。

このPRでやっている事はアウトライン解析処理を強化するやり方ではなくて、 CColorStrategy クラスを継承した CColor_CPreprocessor クラスを新規に作成してプリプロセッサで無効化される行位置を mcpp 側で調べて色分け処理で使うようにしています。

ただし色分けの開始チェック呼び出しの CColor_CPreprocessor::BeginColor はかなりの頻度で呼び出しされるのでそこで mcpp の呼び出しを毎回行うわけにはいきません。そこでレイアウト処理である CLayoutMgr::_DoLayoutCLayoutMgr::DoLayout_RangeCColor_CPreprocessor::Update への呼び出しを追加してそのタイミングで mcpp を呼び出すようにしています。

* サクラエディタ本体に統合するうえでは「無効行のフラグ」の扱いをどうするか?が課題なんじゃないかと思っています。現状だと `CDocLine` にフラグ用のメンバを追加したりしないといけなくて、アクセス用の専用クラスも用意する必要があります。まー、もうちょいあとの話になる感じ。

無効行フラグをCDocLine にメンバ追加して結び付けるべきかどうかは悩み処ですね。Cプリプロセッサの記述によっては1文字記述を変えるだけで、広範囲の行の有効無効が一気に切り替わってしまう事があり得ます。でも全ての編集操作でそういう事態が生じるわけではないし、結び付けた方が良いかな。。

サクラエディタ本体側の文書を解析する機能を強化していくのかは難しいと思いますが、でもちゃんと本体側を機能強化した方が自然でいびつさが無いですね。例えば無効行のコードに関してアウトライン解析での関数一覧抽出が働くべきかどうかという事もあります。

カーソルが括弧の上にいる時に Ctrl + ] キーを押すと対応する括弧の位置に移動しますが、#ifdef 等のプリプロセッサでも同じように位置を切り替えられたら良いなと思ってます。Visual Studio のエディタだとそれが出来ます。

#ifdef に関しては「折り畳み機能」の要望が昔からある気がします。
折り畳み実現のためにも、なんとか本体側に解析したデータ構造を渡したいです。

そういえば折り畳み機能もありましたね。要望のIssueは #824 ですね。
自分はVSのエディタの折り畳み機能を使っていないのでその発想がありませんでした。

小ネタ・・・
windows的には、メモリ≒仮想メモリ≒メモリマップトファイルなので、
乱暴にいってしまえば「メモリ≒ファイル」です。

Windows の 32bit 版でもアドレス空間のサイズを超えた大きさのファイルを扱う事は出来たので、その説明はMMR並みに強引ではないでしょうか?

プログラマが「メモリ」と認識するものは、「物理メモリにマップされた仮想メモリ」という「仮想メモリ」を特殊化した概念です。仮想メモリの作成時に具体的な「マップされるファイルのファイルハンドル」を指定しないと、windowsが「閉じるとき削除する一時ファイル」を作成します。なので、プログラマが「メモリ」と認識するものの実体は、実はファイルです。。。

WindowsのどのAPIの事を言っているんでしょうか?仮想メモリの作成って通常は VirtualAlloc で メモリマップは CreateFileMapping や MapViewOfFile ですけれど。

windowsが「閉じるとき削除する一時ファイル」を作成します。

え、それって本当ですか?それはファイルシステムから見えるものですか?

この辺は boost の inter process communication 周辺が参考になると思います。

一体どこのページに書かれているんでしょうか?

@beru
Copy link
Contributor Author

beru commented Nov 3, 2019

FILE_FLAG_DELETE_ON_CLOSE を指定してファイル作成すると他から読み取りが出来ないので、作成したハンドルを元に処理していくしかないようです。。少し厄介。。

何を試みてるかが分かれば打開策を提案できるかも・・・。

このPRでは mcpp を利用していますが、mcpp の入力がファイル名(argc, argv)なので、現在編集している文書を一時ファイルに書き出しているんです。書き出すのに利用している処理が CWriteManager::WriteFile_From_CDocLineMgr です。

用途としては一時ファイルなので実際にドライブ上にファイルを作成をしてしまうと無駄が多いので、ドライブには書き出さずにメモリ上だけにデータが置かれているファイルを作成出来ればと思いました。

調べたところ WindowsAPI の CreateFile に FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE を指定する事でなるべくドライブに書き出しがされない事が分かりました。しかしそうして作成したファイルは share する事が出来ないようなので、CWriteManager::WriteFile_From_CDocLineMgr や mcpp で利用する事が出来ませんでした。

まぁこうなったら CWriteManager::WriteFile_From_CDocLineMgr を使わずに編集している文書の内容をメモリにコピーして、mcpp 側のコードも改造してファイルからだけでなくメモリからも入力出来るようにしようと思います。

@beru beru changed the title mcpp を使用してCプリプロセッサで無効化された箇所の色分け機能を強化 WIP: mcpp を使用してCプリプロセッサで無効化された箇所の色分け機能を強化 Nov 3, 2019
@beru beru changed the title WIP: mcpp を使用してCプリプロセッサで無効化された箇所の色分け機能を強化 [WIP] mcpp を使用してCプリプロセッサで無効化された箇所の色分け機能を強化 Nov 3, 2019
@beru
Copy link
Contributor Author

beru commented Nov 3, 2019

編集の度に mcpp の呼び出しを行っているとファイルの規模が少し大きくなるとレスポンスが悪化するのが体感出来ちゃいます。という事でアウトライン解析みたいにたまに呼び出す分には問題無いと思いますが、文字入力毎に呼び出すのには無理が有りそうです。

考えられる簡易的な対策としては、行位置が変わるような変更やプリプロセッサ関連の記述が変わったタイミングに限定して呼び出す事ですが、、、まぁそもそも mcpp で丸ごとファイルを処理するのを高頻度で呼び出す事に無理があるのかも。。。

内部実装でCプリプロセッサの記述の解析を編集内容に応じた差分処理で行うようにしないと処理時間の問題は解決できないかな。。

@AppVeyorBot
Copy link

Build sakura 1.0.2370 failed (commit 194b3ec5f1 by @beru)

@berryzplus
Copy link
Contributor

FILE_FLAG_DELETE_ON_CLOSE を指定してファイル作成すると他から読み取りが出来ないので、作成したハンドルを元に処理していくしかないようです。。少し厄介。。

何を試みてるかが分かれば打開策を提案できるかも・・・。

このPRでは mcpp を利用していますが、mcpp の入力がファイル名(argc, argv)なので、現在編集している文書を一時ファイルに書き出しているんです。書き出すのに利用している処理が CWriteManager::WriteFile_From_CDocLineMgr です。

コードはまだ見てないっす(汗;

シグニチャ的にmain関数にあたるものを利用してる気がしました。
main関数でパラメータ解析をしたあと、実際にファイルを開いてメイン処理に入る部分があると思うんですが、そこから先を使うようにしたらいいんじゃないかと思います。

C言語は比較的新しい言語ので、「入力の抽象化」という概念が存在しています。
いわゆる「高水準入力関数」が存在しているので、入力がパンチカードや磁気テープでなくても動作できるようなプログラムを作成できたはずです。組み方によっては、入力がstdinであってもファイルであっても同じコードで動く関数を作れます。

CreatePipe関数 でパイプを作って、open_osfhandle で fd 作って _fdopen したら FILE* ができるので、高水準入出力関数(fprintfとか)を使える状態になります。

読み取り側のグルーコードを書いてやれば、パイプ経由でデータを受け渡しできるようになるのでファイルを作らなくてもよくなります。

@berryzplus
Copy link
Contributor

最初はC言語か何かの関数名一覧をリストアップする実装だったんですかね?

たぶんCOBOL向けじゃないっすかね。
PL/SQL が原点だった可能性も高いと思っています。

実行タイミングが正しい正しくない、については元々のデザインというか仕様ではそのタイミングで行うって決めた事なので、正解というのは無いかもしれません。

それはもっともな意見だと思います。
ぼくが言ってるのは、現在知りうる情報を総合して正しい(=目的を達成するために適切である)と思うかどうかの話で、たぶん正しくはないって思うということです。

小ネタ・・・
windows的には、メモリ≒仮想メモリ≒メモリマップトファイルなので、
乱暴にいってしまえば「メモリ≒ファイル」です。

Windows の 32bit 版でもアドレス空間のサイズを超えた大きさのファイルを扱う事は出来たので、その説明はMMR並みに強引ではないでしょうか?

Windowsの仮想メモリは、全体の一部を必要なときにコミットして使うようになってます。
だから、超巨大なファイルの一部だけをマップすることも可能です。

プログラマが「メモリ」と認識するものは、「物理メモリにマップされた仮想メモリ」という「仮想メモリ」を特殊化した概念です。仮想メモリの作成時に具体的な「マップされるファイルのファイルハンドル」を指定しないと、windowsが「閉じるとき削除する一時ファイル」を作成します。なので、プログラマが「メモリ」と認識するものの実体は、実はファイルです。。。

WindowsのどのAPIの事を言っているんでしょうか?仮想メモリの作成って通常は VirtualAlloc で メモリマップは CreateFileMapping や MapViewOfFile ですけれど。

windowsのPEローダーはプロセス空間を作るときに仮想メモリの枠組みを使います。
GlobalヒープやProcessヒープという概念もありますが、それらもすべて、大元は仮想メモリです。

windowsが「閉じるとき削除する一時ファイル」を作成します。

え、それって本当ですか?それはファイルシステムから見えるものですか?

たしか %TEMP% に吐かれる仕様だったはず。
ちょっと怪しいです。

この辺は boost の inter process communication 周辺が参考になると思います。

一体どこのページに書かれているんでしょうか?

これっす。 https://www.boost.org/doc/libs/1_63_0/doc/html/interprocess.html

@beru
Copy link
Contributor Author

beru commented Nov 4, 2019

コードはまだ見てないっす(汗;

シグニチャ的にmain関数にあたるものを利用してる気がしました。
main関数でパラメータ解析をしたあと、実際にファイルを開いてメイン処理に入る部分があると思うんですが、そこから先を使うようにしたらいいんじゃないかと思います。

mcpp_lib_main が main 関数にあたるものです。

そこから呼び出しているメインループにあたるのは mcpp_main 関数ですね。
ただその関数は公開関数ではなく情報もグローバル経由で渡す作りです。

現時点で最新のコミット 29d0043 では mcpp 側の記述を更新してファイル入力処理の関数を外部から指定したコールバック関数を使えるようにしました。そして一時ファイルを作らないように変更しました。

具体的には新たに追加した公開関数 mcpp_set_in_func で fopen, fgets, fclose, ferror の置き換えとなるコールバック関数を設定出来るようにしています。CColor_CPreprocess.cpp ファイル内で fgets の置き換え用の関数が呼ばれるたびに CDocLine* の行データを出力先に書いてからリストを進めるようにしてます。

C言語は比較的新しい言語ので、「入力の抽象化」という概念が存在しています。
いわゆる「高水準入力関数」が存在しているので、入力がパンチカードや磁気テープでなくても動作できるようなプログラムを作成できたはずです。組み方によっては、入力がstdinであってもファイルであっても同じコードで動く関数を作れます。

CreatePipe関数 でパイプを作って、open_osfhandle で fd 作って _fdopen したら FILE* ができるので、高水準入出力関数(fprintfとか)を使える状態になります。

読み取り側のグルーコードを書いてやれば、パイプ経由でデータを受け渡しできるようになるのでファイルを作らなくてもよくなります。

http://www.langedge.jp/blog/index.php?itemid=652

に書かれているやり方に近いですね。そのやり方の場合は mcpp 側を改造して、入力ファイルの FILE* を引数とする公開関数を用意しないといけないです。mcppのライブラリとしてのI/Fは色々なケースを考慮して整備されているわけじゃないので、しゃあないですね。

@beru
Copy link
Contributor Author

beru commented Nov 4, 2019

最初はC言語か何かの関数名一覧をリストアップする実装だったんですかね?

たぶんCOBOL向けじゃないっすかね。
PL/SQL が原点だった可能性も高いと思っています。

おー実務向けですね。しかし今となっては結構力不足感がありますね。C++の複雑な構文とかには対応出来てないし。いやまぁ対応するのが結構無理な感じがありますが…。

それはもっともな意見だと思います。
ぼくが言ってるのは、現在知りうる情報を総合して正しい(=目的を達成するために適切である)と思うかどうかの話で、たぶん正しくはないって思うということです。

正誤というわけではなくて、やりたい事を実現するのに適した枠組みではない、という事ですよね?

どこまでの機能を実現したいかを定義して、それを実現させる為にはどういうデザインにするかを決めて I/F を整備して、そこから様々な文書種別に応じた実装を進める、となると長い道のりに見えますね…。

Windows の 32bit 版でもアドレス空間のサイズを超えた大きさのファイルを扱う事は出来たので、その説明はMMR並みに強引ではないでしょうか?

Windowsの仮想メモリは、全体の一部を必要なときにコミットして使うようになってます。
だから、超巨大なファイルの一部だけをマップすることも可能です。

それはファイルの内容をマップする場合にそういう見方も出来るよ的な限定したケースの話ですよね。ファイルの内容をDRAMにキャッシュせずにシーケンシャルに読み書きする使い方も出来るので、そういう場合には メモリ = ファイル という概念的な見方が出来なくなるかなと。。

WindowsのどのAPIの事を言っているんでしょうか?仮想メモリの作成って通常は VirtualAlloc で メモリマップは CreateFileMapping や MapViewOfFile ですけれど。

windowsのPEローダーはプロセス空間を作るときに仮想メモリの枠組みを使います。
GlobalヒープやProcessヒープという概念もありますが、それらもすべて、大元は仮想メモリです。

それはそうなんですけど、それがどうして メモリ = ファイル になるんでしょうか?
包含関係とかすっとばして単純化してませんか?

え、それって本当ですか?それはファイルシステムから見えるものですか?

たしか %TEMP% に吐かれる仕様だったはず。
ちょっと怪しいです。

仮想メモリの確保ってページ単位で行えるのでその度にファイルシステムへのエントリは作成は出来ないでしょうね。なので下記の内容はちょっと理解出来てません。

仮想メモリの作成時に具体的な「マップされるファイルのファイルハンドル」を指定しないと、windowsが「閉じるとき削除する一時ファイル」を作成します。

いやまぁ再現するプログラムコードがあって動かしたら本当にそうなるなら信じざるを得ませんけれど。。でもそのまえにMicrosoftのサイトのWindowsAPIの解説部分にそういう説明が有る筈。

一体どこのページに書かれているんでしょうか?

これっす。 https://www.boost.org/doc/libs/1_63_0/doc/html/interprocess.html

ぴゃー、長い。

@beru
Copy link
Contributor Author

beru commented Nov 4, 2019

このPRでは Cプリプロセッサの解析を mcpp という外部ライブラリに任せるやり方にしてますが、編集操作で毎回文書丸ごとを処理させると、連続操作時のレスポンスが悪くなってしまうので、このやり方は良くなさそうです。

あとタイプ別設定のカラーの色指定のリストに Cプリプロセッサ が入るのも、場違いかもしれません。

これからどう進めるか悩みどころなので対策案を書き連ねてみました。

対策案0 このままの無理やり実装のまま進める

  • 現在のこのRPの方向性のまま進める。
  • mcpp の呼び出し頻度はなるべく無駄に実行しないように編集内容に応じて呼ぶべきでない編集内容の場合は呼ばないようにする。
    • その判定が難しそうだけど…。
  • 無理やり実装なので恣意的な記述がサクラエディタ本体のコードにどんどん追加されてしまいます。

対策案 1 やっつけ対応

  • ブックマークのように行単位でフラグ設定出来る仕様を追加で入れてコマンドで設定出来るようにする
    • 行単位のフラグは CDocLine::MarkType にメンバーを追加するやり方で実現
    • タイプ別設定のカラーの色指定のリストには Cプリプロセッサ という具体的な名前ではなく行フラグ1 ~ 行フラグ8 の項目を追加して用途によって自由に使えるものにする。
      • 行の色の付け方も良し悪しが有りそう。
  • マクロやプラグインで mcpp の処理結果を元に追加したコマンドを呼び出して無効行に対してフラグを立てる事で色変えを実現

メリット

  • 実現するのが比較的容易
    • サクラエディタ側にCプリプロセッサの解析処理を新たに入れる必要は無い
  • ユーザー指示のタイミングで呼び出しがされるので頻度が少なく処理負荷が低い

デメリット

  • ユーザー指示のタイミングで更新しないとCプリプロセッサによる無効行表示が正しく更新されない
  • エディタ側はCプリプロセッサの解釈自体はしていないので下記のような事は実現出来ない(対策案0 でも同様だけれど)
    • カーソルが括弧の上にいる時に Ctrl + ] キーを押すと対応する括弧の位置に移動、#ifdef 等のプリプロセッサでも同じように位置を切り替えられたら良い
    • #ifdef 等のCプリプロセッサ部分も将来的に入れるかもしれない折り畳み機能で扱う対象にしたい
    • アウトライン解析でCプリプロセッサで無効化されている部分を対象外に出来るようにしたい
  • 一般のテキストエディタのユーザーが行にフラグを付けたいニーズというのは殆ど無いと考えられるため、汎用的なフラグをUIに出すと分かりづらくなる

対策案 2 ガチ実装

Cプリプロセッサの解析処理を mcpp を参考にして書き起こしサクラエディタ本体に組み込んで、色付けやアウトライン解析を含めて強化する。やりたい事を実現するにあたって正面突破する方法。

メリット

  • 自前実装にすれば細かいコントロールが効くし、編集差分に応じた必要最小限の処理に済ます事が出来るはずなので負荷も低くレスポンスも良いものに出来る可能性が有る

デメリット

  • 実装が大変

@AppVeyorBot
Copy link

Build sakura 1.0.2373 completed (commit 4f134c40b4 by @)

グローバル変数 mcpp_ifdef_false_lines を削除
各行毎のフラグを mcpp_ifdef_false_lines 配列変数に持つのではなく CDocLine::MarkType構造体に m_bExcludedByCPreprocessor メンバーを追加してそこに記録するように変更

CLayoutMgr::DoLayout_Range で CColor_CPreprocessor::Update を呼び出すのは止める。文字入力毎にCプリプロセッサを実行すると重過ぎる為

グローバル変数 g_CColorStrategy_nCurLine を削除
CLayoutMgr::_MakeOneLine において CheckColorMODE を呼び出す前にグローバル変数 g_CColorStrategy_nCurLine を設定していたのは止める。
後述する方法により色変えを出来ると判断

グローバル変数 g_pDocLineDrawing を追加
CEditView::DrawLogicLine で新規追加したグローバル変数 を g_pDocLineDrawing 設定
描画時に SColorStrategyInfo::CheckChangeColor が呼び出される事を利用した仕組み

mcpp/system.c の norm_path 関数で正規化したパスが元のファイル名と同じ場合はメモリ解放して NULL を返すように変更
メモリリークへの対処
@AppVeyorBot
Copy link

Build sakura 1.0.2376 failed (commit a2fafd23f1 by @)

</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
<IntDir>$(Platform)\$(Configuration)\</IntDir>
<LinkIncremental>true</LinkIncremental>
<IncludePath>C:\Program Files (x86)\Visual Leak Detector\include;$(IncludePath)</IncludePath>
<LibraryPath>C:\Program Files (x86)\Visual Leak Detector\lib\Win64;$(LibraryPath)</LibraryPath>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こういうことなんじゃないかな?と思ったり・・・。

   <PropertyGroup> 
        <IncludePath>$(ProgramFiles)\Visual Leak Detector\include;$(IncludePath)</IncludePath> 
   </PropertyGroup> 
   <PropertyGroup Condition="'$(Platform)'=='x64'"> 
        <LibraryPath>$(ProgramFiles)\Visual Leak Detector\lib\Win64;$(LibraryPath)</LibraryPath> 
   </PropertyGroup> 

Copy link
Contributor Author

@beru beru Nov 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

それは確かに。Win64ビルドでしか確認していないのでこんな設定になっています。。
まぁ本来は Visual Leak Detector に関する変更はコミットから外すべきなのですが…。

しかしこのPRの変更内容が実験的なものになってしまってます。いつかはまともなものにしたい。:cry:

@AppVeyorBot
Copy link

Build sakura 1.0.2377 failed (commit b51da4312e by @beru)

@AppVeyorBot
Copy link

Build sakura 1.0.2378 failed (commit 7c47cbb139 by @)

失敗時に mcpp が中断してしまう事が無いようにする為
@AppVeyorBot
Copy link

Build sakura 1.0.2379 failed (commit 5c40efc2d6 by @beru)

Cプリプロセッサで無効化された複数行のコメントの色分けが適切に行われるように処理追加
行挿入時に隣接行のCプリプロセッサで無効化フラグをコピーする処理追加
CLayoutMgr::_MakeOneLine メソッドで g_pDocLineDrawing を設定する記述追加、ここに入れないと編集時に正しく描画されない
@AppVeyorBot
Copy link

Build sakura 1.0.2380 failed (commit 9c87363744 by @beru)

@beru
Copy link
Contributor Author

beru commented Nov 17, 2019

mcpp に頼るのではなくサクラエディタ本体側のCプリプロセッサの解釈をちゃんと強化しないと駄目だなと思うのでこのPRは close します。

現在のサクラエディタでは以下のようなコードで色変えが変になります。

image

@beru beru closed this Nov 17, 2019
@beru beru deleted the CPreprocessor branch November 17, 2019 11:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants