aboutsummaryrefslogtreecommitdiffstats
path: root/docs/ja/coding_conventions_c.md
blob: fccd44a3ae0850266ac029b3a1dd05b8069ff162 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# コーディング規約 (C)

<!---
  original document: 0.9.19:docs/coding_conventions_c.md
  git diff 0.9.19 HEAD -- docs/coding_conventions_c.md | cat
-->

私たちのスタイルのほとんどはかなり理解しやすいですが、現時点では完全に一貫しているわけではありません。変更箇所周辺のコードのスタイルと一致させる必要がありますが、そのコードに一貫性が無い場合や不明瞭な場合は以下のガイドラインに従ってください:

* 4つのスペース (ソフトタブ) を使ってインデントします。
* 修正版 One True Brace Style を使います。
   * 開き括弧: ブロックを開始する文と同じ行の最後
   * 閉じ括弧: ブロックを開始した文と同じ字下げ
   * Else If: 行の先頭に閉じ括弧を置き、次の開き括弧を同じ行の最後に置きます。
   * 省略可能な括弧: 常に括弧を付け加えます。
      * 良い: if (condition) { return false; }
      * 悪い: if (condition) return false;
* C 形式のコメントの使用を推奨します: `/* */`
   * コメントを機能を説明するストーリーと考えて下さい。
   * 特定の決定がなされた理由を充分なコメントで説明してください。
   * 分かり切ったコメントは書かないでください。
   * 分かり切ったコメントであるか確信できない場合は、コメントを含めてください。
* 一般的に、行を折り返さないで、必要なだけ長くすることができます。行を折り返すことを選択した場合は、76列を超えて折り返さないでください。
* 古い形式のインクルードガード (`#ifndef THIS_FILE_H``#define THIS_FILE_H`、...、`#endif`) ではなく、ヘッダファイルの先頭で `#pragma once` を使います。
* プリプロセッサ if の両方の形式を受け付けます: `#ifdef DEFINED``#if defined(DEFINED)`
   * どちらがいいかわからない場合は、`#if defined(DEFINED)` 形式を使ってください。
   * 複数の条件 `#if` に移行する場合を除き、既存のコードを別のスタイルに変更しないでください。
* プリプロセッサディレクティブをインデントする方法(あるいはするかどうか)を決定する時は、以下の事に留意してください:
   * 一貫性よりも読みやすさが重要です。
   * ファイルの既存のスタイルに従ってください。ファイルのスタイルが混在している場合は、修正しようとしているセクションに適したスタイルに従ってください。
   * インデントする時は、ハッシュを行の先頭に置き、`#` と `if` の間に空白を追加します。`#` の後ろに4つスペースを入れて開始します。
   * 周りの C コードのインデントレベルに従うか、プリプロセッサのディレクティブに独自のインデントレベルを設定することができます。コードの意図を最もよく伝えるスタイルを選択してください。

わかりやすいように例を示します:

```c
/* Enums for foo */
enum foo_state {
    FOO_BAR,
    FOO_BAZ,
};

/* Returns a value */
int foo(void) {
    if (some_condition) {
        return FOO_BAR;
    } else {
        return -1;
    }
}
```

# clang-format を使った自動整形

[Clang-format](https://clang.llvm.org/docs/ClangFormat.html) は LLVM の一部で、誰もが手動で整形するほど暇ではないため、コードを自動整形することができます。私たちは、上記のコーディング規約のほとんどを適用する設定ファイルを提供しています。空白と改行のみを変更するため、省略可能な括弧は自分で付け加えることを忘れないでください。

Windows で clang-format を入手するには [full LLVM インストーラ](http://llvm.org/builds/)を使い、Ubuntu では `sudo apt install clang-format` を使ってください。

コマンドラインから実行する場合、オプションとして `-style=file` を渡すと、QMK ルートディレクトリ内の .clang-format 設定ファイルを自動的に見つけます。

VSCode を使う場合は、標準の C/C++ プラグインが clang-format をサポートしますが、その他にも [独立した拡張機能](https://marketplace.visualstudio.com/items?itemName=LLVMExtensions.ClangFormat) があります。

幾つかのコード (LAYOUT マクロのような)が clang-format によって破壊されるため、これらのファイルで clang-format を実行しないか、整形したくないコードを `// clang-format off``// clang-format on` で囲みます。
>float ) def __str__(self): return self.msg def __repr__(self): return self.msg @classmethod def from_state(cls, state): # the default implementation assumes an empty constructor. Override # accordingly. f = cls(None) f.set_state(state) return f class Flow(stateobject.StateObject): """ A Flow is a collection of objects representing a single transaction. This class is usually subclassed for each protocol, e.g. HTTPFlow. """ def __init__( self, type: str, client_conn: connections.ClientConnection, server_conn: connections.ServerConnection, live: bool=None ) -> None: self.type = type self.id = str(uuid.uuid4()) self.client_conn = client_conn self.server_conn = server_conn self.live = live self.error = None # type: typing.Optional[Error] self.intercepted = False # type: bool self._backup = None # type: typing.Optional[Flow] self.reply = None # type: typing.Optional[controller.Reply] self.marked = False # type: bool self.metadata = dict() # type: typing.Dict[str, typing.Any] _stateobject_attributes = dict( id=str, error=Error, client_conn=connections.ClientConnection, server_conn=connections.ServerConnection, type=str, intercepted=bool, marked=bool, metadata=dict, ) def get_state(self): d = super().get_state() d.update(version=version.FLOW_FORMAT_VERSION) if self._backup and self._backup != d: d.update(backup=self._backup) return d def set_state(self, state): state = state.copy() state.pop("version") if "backup" in state: self._backup = state.pop("backup") super().set_state(state) @classmethod def from_state(cls, state): f = cls(None, None) f.set_state(state) return f def copy(self): f = super().copy() f.live = False if self.reply is not None: f.reply = controller.DummyReply() return f def modified(self): """ Has this Flow been modified? """ if self._backup: return self._backup != self.get_state() else: return False def backup(self, force=False): """ Save a backup of this Flow, which can be reverted to using a call to .revert(). """ if not self._backup: self._backup = self.get_state() def revert(self): """ Revert to the last backed up state. """ if self._backup: self.set_state(self._backup) self._backup = None @property def killable(self): return self.reply and self.reply.state == "taken" def kill(self): """ Kill this request. """ self.error = Error("Connection killed") self.intercepted = False # reply.state should be "taken" here, or .take() will raise an # exception. if self.reply.state != "taken": self.reply.take() self.reply.kill(force=True) self.reply.commit() self.live = False def intercept(self): """ Intercept this Flow. Processing will stop until resume is called. """ if self.intercepted: return self.intercepted = True self.reply.take() def resume(self): """ Continue with the flow - called after an intercept(). """ if not self.intercepted: return self.intercepted = False # If a flow is intercepted and then duplicated, the duplicated one is not taken. if self.reply.state == "taken": self.reply.ack() self.reply.commit()