Closed psmuler closed 1 year ago
ブランチを切り替えた際に、そのブランチの最新のコミットを取得し、ファイルを表示するようにするには、以下の手順に従います。
renderer.js
に以下のコードを追加して、上記の手順を実行します。
// ブランチ選択時の処理
branchSelect.addEventListener('change', async () => {
const selectedBranch = branchSelect.options[branchSelect.selectedIndex].value;
const folderPath = folderPathSpan.textContent;
// 選択されたブランチにチェックアウト
await new Promise((resolve, reject) => {
exec(`git -C "${folderPath}" checkout "${selectedBranch}"`, (error, stdout, stderr) => {
if (error) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
if (stderr) {
console.error(`Stderr: ${stderr}`);
reject(new Error(stderr));
return;
}
console.log(`Branch switched: ${stdout}`);
resolve();
});
});
// 最新のコミットからファイルを読み込み
const fileContent = await new Promise((resolve, reject) => {
fs.readFile(`${folderPath}/${currentFileName}`, 'utf-8', (error, data) => {
if (error) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
resolve(data);
});
});
// テキストエディタにファイル内容を表示
textEditor.value = fileContent;
});
このコードは、ブランチ選択プルダウンでブランチが選択されたときに実行されるイベントリスナを追加します。選択されたブランチにチェックアウトし、最新のコミットからファイルを読み込んでテキストエディタに表示します。
Stderr: Switched to branch 'main'
(anonymous) @ renderer.js:41 renderer.js:42 Uncaught (in promise) Error: Switched to branch 'main'
at renderer.js:42:24
at ChildProcess.exithandler (node:child_process:422:7)
at ChildProcess.emit (node:events:513:28)
at maybeClose (node:internal/child_process:1091:16)
at Socket.<anonymous> (node:internal/child_process:449:11)
at Socket.emit (node:events:513:28)
at Pipe.<anonymous> (node:net:322:12)
ブランチの切り替え時に発生するメッセージがエラー扱いのため、先に進めません。
Switched to branch 'main'
メッセージがstderr
で出力されるのは想定外ですが、このメッセージはエラーではなく、実際には成功メッセージです。この問題を解決するために、exec
のstderr
に対して条件を追加して、特定の成功メッセージをエラーとして扱わないようにしましょう。
renderer.js
内のexec
関数を以下のように書き換えてください。
// 選択されたブランチにチェックアウト
await new Promise((resolve, reject) => {
exec(`git -C "${folderPath}" checkout "${selectedBranch}"`, (error, stdout, stderr) => {
if (error) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
if (stderr && !stderr.startsWith('Switched to branch')) {
console.error(`Stderr: ${stderr}`);
reject(new Error(stderr));
return;
}
console.log(`Branch switched: ${stdout}${stderr}`);
resolve();
});
});
これにより、stderr
の内容がSwitched to branch
で始まる場合、エラーとして扱わなくなります。それ以外の場合は、従来通りエラーとして扱われます。
Stderr: Switched to branch 'main'
(anonymous) @ renderer.js:41 renderer.js:42 Uncaught (in promise) Error: Switched to branch 'main'
at renderer.js:42:24
at ChildProcess.exithandler (node:child_process:422:7)
at ChildProcess.emit (node:events:513:28)
at maybeClose (node:internal/child_process:1091:16)
at Socket.<anonymous> (node:internal/child_process:449:11)
at Socket.emit (node:events:513:28)
at Pipe.<anonymous> (node:net:322:12)
ブランチの切り替え時に発生するメッセージがエラー扱いのため、先に進めません。exit status が 0かどうかなどをもとにエラーでないかどうか判断するようにできますか。
確かに、Switched to branch 'main'
のメッセージはエラーではなく、正常なメッセージです。この問題を解決するために、exec
のコールバック関数内でerror
オブジェクトのcode
プロパティをチェックし、それが0であるかどうかを確認しましょう。code
が0であれば、エラーとはみなさずに処理を続行します。
renderer.js
のブランチ選択時の処理を以下のように修正してください。
// ブランチ選択時の処理
branchSelect.addEventListener('change', async () => {
const selectedBranch = branchSelect.options[branchSelect.selectedIndex].value;
const folderPath = folderPathSpan.textContent;
// 選択されたブランチにチェックアウト
await new Promise((resolve, reject) => {
exec(`git -C "${folderPath}" checkout "${selectedBranch}"`, (error, stdout, stderr) => {
if (error && error.code !== 0) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
if (stderr) {
console.error(`Stderr: ${stderr}`);
}
console.log(`Branch switched: ${stdout}`);
resolve();
});
});
// 最新のコミットからファイルを読み込み
const fileContent = await new Promise((resolve, reject) => {
fs.readFile(`${folderPath}/${currentFileName}`, 'utf-8', (error, data) => {
if (error) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
resolve(data);
});
});
// テキストエディタにファイル内容を表示
textEditor.value = fileContent;
});
この修正により、エラーが発生しているかどうかを正しく判断できるようになります。
branchSelect.addEventListener('change', async () => {のif(branchSelect.value === 'create-new-branch')でipcRenderer.invoke('show-branch-input-dialog');を待っている間にもそれ以下のコードが実行されてしまいエラーになってしまいます。
await new Promise((resolve, reject) => {
exec(git -C "${folderPath}" checkout "${selectedBranch}"
, (error, stdout, stderr) => {
if (error && error.code !== 0) {
console.error(Error: ${error.message}
);
reject(error);
return;
}
if (stderr) {
console.error(Stderr: ${stderr}
);
}
console.log(Branch switched: ${stdout}
);
resolve();
});
});
branchSelect.addEventListener('change', async () => {
の処理でipcRenderer.invoke('show-branch-input-dialog');
を待機するように修正するために、change
イベントリスナーの中でbranchSelect.value === 'create-new-branch'
の条件が満たされた場合、Promise
を返す関数を定義してawait
を使って待機しましょう。
以下のようにコードを修正してください。
// ブランチ選択時の処理
branchSelect.addEventListener('change', async () => {
const selectedBranch = branchSelect.options[branchSelect.selectedIndex].value;
const folderPath = folderPathSpan.textContent;
if (selectedBranch === 'create-new-branch') {
// show-branch-input-dialogを待機するPromiseを定義
const waitForBranchInputDialog = async () => {
return new Promise((resolve) => {
ipcRenderer.once('branch-input-dialog-closed', () => {
resolve();
});
});
};
// ダイアログが閉じるのを待つ
await ipcRenderer.invoke('show-branch-input-dialog');
await waitForBranchInputDialog();
// ブランチリストを更新
await updateBranchList();
return;
}
// 選択されたブランチにチェックアウト
await new Promise((resolve, reject) => {
exec(`git -C "${folderPath}" checkout "${selectedBranch}"`, (error, stdout, stderr) => {
if (error && error.code !== 0) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
if (stderr) {
console.error(`Stderr: ${stderr}`);
}
console.log(`Branch switched: ${stdout}`);
resolve();
});
});
// 最新のコミットからファイルを読み込み
const fileContent = await new Promise((resolve, reject) => {
fs.readFile(`${folderPath}/${currentFileName}`, 'utf-8', (error, data) => {
if (error) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
resolve(data);
});
});
// テキストエディタにファイル内容を表示
textEditor.value = fileContent;
});
この修正により、branch-input-dialog-closed
イベントが発生するまで、後続のコードの実行が待機されます。これでエラーが発生しなくなります。
できました。 追跡しているブランチのコミットを右側ペインを作成し、表示する機能をつけましょう
まず、index.htmlに新たなペインを作成し、コミット一覧を表示する領域を作りましょう。
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Electron App</title>
</head>
<body>
<!-- 省略 -->
<div id="main">
<textarea id="text-editor"></textarea>
<!-- 追加: コミット一覧を表示する右側ペイン -->
<div id="commit-list-pane">
<h3>Commit List</h3>
<ul id="commit-list"></ul>
</div>
</div>
<script src="renderer.js"></script>
</body>
</html>
次に、renderer.jsに、選択されたブランチのコミット一覧を表示する関数を作成しましょう。
renderer.js:
// 省略
// 選択されたブランチのコミット一覧を表示
async function showCommitList() {
const selectedBranch = branchSelect.options[branchSelect.selectedIndex].value;
const folderPath = folderPathSpan.textContent;
if (!folderPath || selectedBranch === 'create-new-branch') {
return;
}
const commitLogOutput = await new Promise((resolve, reject) => {
exec(`git -C "${folderPath}" log --pretty=format:"%h - %s" ${selectedBranch}`, (error, stdout, stderr) => {
if (error && error.code !== 0) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
if (stderr) {
console.error(`Stderr: ${stderr}`);
}
resolve(stdout);
});
});
const commitList = document.getElementById('commit-list');
commitList.innerHTML = '';
const commitLines = commitLogOutput.split('\n');
commitLines.forEach((commitLine) => {
const listItem = document.createElement('li');
listItem.textContent = commitLine;
commitList.appendChild(listItem);
});
}
// 省略
branchSelect.addEventListener('change', async () => {
// 省略
// ブランチを切り替えた後、コミット一覧を表示
await showCommitList();
});
このコードは、選択されたブランチのコミット一覧を取得し、コミットのハッシュとサブジェクト(1行の説明)を表示します。branchSelect
イベントリスナーの中でshowCommitList()
関数を呼び出すことで、ブランチを切り替えるたびにコミット一覧が更新されるようになります。
追加で、CSSを適用してコミット一覧ペインとテキストエディタが横並びになるようにしましょう。
styles.css:
/* 省略 */
#main {
display: flex;
width: 100%;
}
#text-editor {
flex: 1;
resize: none;
width: 100%;
height: 100%;
}
次に、コミット一覧ペインにスタイルを追加して、テキストエディタと横並びに表示されるようにしましょう。
styles.css:
#commit-list-pane {
width: 300px;
padding: 1rem;
border-left: 1px solid #ccc;
}
#commit-list {
list-style-type: none;
padding: 0;
margin: 0;
}
これで、テキストエディタとコミット一覧ペインが横並びに表示され、ブランチを切り替えるたびにコミット一覧が更新されるようになります。
index.htmlでstyles.cssをインポートしましょう
index.html
にstyles.css
をインポートするには、<head>
タグ内に<link>
タグを追加します。
index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Markdown Git Editor</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- 以前のコード -->
</body>
</html>
このようにして、styles.css
をindex.html
にインポートすることができます。これにより、定義したスタイルが適用されるようになります。
text-editorの高さが小さくなってしまいました
すみません、それは私のミスです。#text-editor
のスタイルを修正しましょう。height: 100%;
を削除し、flex-grow: 1;
を追加してください。これにより、テキストエディタが残りの空間を占めるようになります。
styles.css:
#text-editor {
flex-grow: 1;
resize: none;
width: 100%;
}
また、#container
にdisplay: flex;
を追加して、テキストエディタとコミット一覧ペインが横並びに表示されるようにしましょう。
styles.css:
#container {
display: flex;
}
これでテキストエディタの高さが適切になり、画面全体に広がるはずです。
表示が大きくなるようになりましたが、コミットリストが表示されていない状態でもテキストボックス全体が表示されるようにしましょう
すみません、その問題を修正しましょう。#container
のスタイルにflex-grow: 1;
を追加し、コンテナが親要素に対して適切にリサイズされるようにします。
また、body
タグのスタイルにdisplay: flex; flex-direction: column; height: 100vh;
を追加して、コンテナが縦方向に画面全体に広がるようにしましょう。
styles.css:
body {
margin: 0;
display: flex;
flex-direction: column;
height: 100vh;
}
#container {
display: flex;
flex-grow: 1;
}
これで、コミットリストが表示されていない状態でも、テキストボックスが画面全体に広がるようになります。
すみません、#container
に言及したのは私のミスです。代わりに、以下のようにindex.html
の<body>
タグに#app-container
というIDを追加しましょう。
index.html:
<body>
<div id="app-container">
<!-- 以前のコード -->
</div>
</body>
そして、styles.css
に新しく追加した#app-container
に対して、display: flex;
のスタイルを適用しましょう。
styles.css:
#app-container {
display: flex;
}
これで、テキストエディタとコミット一覧ペインが横並びに表示されるようになります。
各コミットを選択できるようにし、選ばれたらそのコミットをエディタに表示するようにしましょう
以下のようにコードを修正し、各コミットを選択できるようにし、選ばれたらそのコミットをエディタに表示するようにしましょう。
renderer.js:
// 省略
// 選択されたコミットの内容を表示
async function showSelectedCommit(commitHash) {
const folderPath = folderPathSpan.textContent;
const fileContent = await new Promise((resolve, reject) => {
exec(`git -C "${folderPath}" show ${commitHash}:${mdFileName}`, (error, stdout, stderr) => {
if (error && error.code !== 0) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
if (stderr) {
console.error(`Stderr: ${stderr}`);
}
resolve(stdout);
});
});
const textEditor = document.getElementById('text-editor');
textEditor.value = fileContent;
}
// 省略
// 選択されたブランチのコミット一覧を表示
async function showCommitList() {
// 省略
const commitLines = commitLogOutput.split('\n');
commitLines.forEach((commitLine) => {
const listItem = document.createElement('li');
listItem.textContent = commitLine;
listItem.addEventListener('click', () => {
const commitHash = commitLine.split(' ')[0];
showSelectedCommit(commitHash);
});
commitList.appendChild(listItem);
});
}
// 省略
このコードでは、各リスト項目にclick
イベントリスナーを追加し、コミットがクリックされたときにshowSelectedCommit
関数が呼び出されるようにしています。showSelectedCommit
関数では、選択されたコミットの内容を取得してエディタに表示しています。
ただし、この方法では過去のコミットを表示している間にエディタで編集が行われると、新しいコミットが上書きされてしまう可能性があります。過去のコミットを表示している間は編集を無効にするか、適切なメッセージを表示してユーザーに注意喚起することを検討してください。
mdFilenameは定義されていません
すみません、mdFileNameが定義されていないことを見落としていました。以下のように修正して、選択されたブランチでの現在の作業ディレクトリの.mdファイルの内容を表示するようにしましょう。
renderer.js:
// 省略
// 選択されたコミットの内容を表示
async function showSelectedCommit(commitHash) {
const folderPath = folderPathSpan.textContent;
// フォルダ内の.mdファイルを探す
const mdFiles = await new Promise((resolve, reject) => {
fs.readdir(folderPath, (err, files) => {
if (err) {
reject(err);
return;
}
resolve(files.filter(file => file.endsWith('.md')));
});
});
if (mdFiles.length === 0) {
console.error('No markdown files found in the folder');
return;
}
const mdFileName = mdFiles[0]; // 最初に見つかった.mdファイルを使用する
const fileContent = await new Promise((resolve, reject) => {
exec(`git -C "${folderPath}" show ${commitHash}:${mdFileName}`, (error, stdout, stderr) => {
if (error && error.code !== 0) {
console.error(`Error: ${error.message}`);
reject(error);
return;
}
if (stderr) {
console.error(`Stderr: ${stderr}`);
}
resolve(stdout);
});
});
const textEditor = document.getElementById('text-editor');
textEditor.value = fileContent;
}
// 省略
// 選択されたブランチのコミット一覧を表示
async function showCommitList() {
// 省略
const commitLines = commitLogOutput.split('\n');
commitLines.forEach((commitLine) => {
const listItem = document.createElement('li');
listItem.textContent = commitLine;
listItem.addEventListener('click', () => {
const commitHash = commitLine.split(' ')[0];
showSelectedCommit(commitHash);
});
commitList.appendChild(listItem);
});
}
// 省略
この修正では、showSelectedCommit
関数内で選択されたフォルダ内の.mdファイルを探し、最初に見つかった.mdファイルをmdFileName
として使用します。この方法で現在の作業ディレクトリの.mdファイルの内容を表示できます。
ただし、複数の.mdファイルが存在する場合は、どのファイルを表示するかをユーザーが選択できるようにすることを検討してください。
ブランチを切り替えたら、そのブランチの最新のコミットを取得してファイルを表示するようにしましょう