/*
Code Studio — source control
Talks to backend/git.agi, which wraps the git AGI library (go-git —
no git binary is needed on the host). The view mirrors the working
tree of whatever project folder is open in the explorer.
*/
var csGitStatus = null; //Last status snapshot, or null when not a repository
var csGitOuterRoot = ""; //Repository the project folder sits inside, if any
var csGitBusy = false;
var csGitAuthRetry = null; //Operation to retry once the user has signed in
function gitcall(operation, data, callback){
var payload = { opr: operation, repo: currentProjectFolder };
for (var key in data){ payload[key] = data[key]; }
$.ajax({
url: "../system/ajgi/interface?script=Code Studio/backend/git.agi",
method: "POST",
data: payload,
dataType: "json",
success: function(response){ callback(response); },
error: function(){ callback({ success: false, error: "Source control backend is unreachable" }); }
});
}
/* ═══════════════════════════════════════════════════════════════════
Status
═══════════════════════════════════════════════════════════════════ */
function refreshGitStatus(){
if (!currentProjectFolder){
csGitStatus = null;
$("#scmBadge").hide();
$("#sbBranch").hide();
$("#scmBody").html('
Open a project folder to see its repository.
');
return;
}
gitcall("status", {}, function(response){
if (!response.success){
csGitStatus = null;
csGitOuterRoot = response.outerRoot || "";
$("#scmBadge").hide();
$("#sbBranch").hide();
renderNoRepository(response.error);
return;
}
csGitOuterRoot = "";
csGitStatus = response.status;
renderScmView(csGitStatus);
applyGitDecorations(csGitStatus);
});
}
//Called after a save or a file open — cheap enough to just re-read the status
function refreshGitDecorations(){
if (!currentProjectFolder || !csGitStatus) return;
gitcall("status", {}, function(response){
if (!response.success) return;
csGitStatus = response.status;
renderScmView(csGitStatus);
applyGitDecorations(csGitStatus);
});
}
function renderNoRepository(errorText){
var isMissingRepo = !errorText || errorText.toLowerCase().indexOf("not a") !== -1 ||
errorText.toLowerCase().indexOf("repository") !== -1;
var body = isMissingRepo ? 'This folder is not a git repository yet.' : escapeHTMLText(errorText);
/*
The opened folder can sit inside someone else's checkout. Source control
deliberately stops at the project folder rather than reaching up into
that repository, so say where it is and offer to open it properly.
*/
if (csGitOuterRoot != ""){
var outerName = csGitOuterRoot.split("/").filter(Boolean).pop();
body += '
It is inside the repository ' + escapeHTMLText(outerName) + ' ' +
'(' + escapeHTMLText(csGitOuterRoot) + '), ' +
'which is outside this project folder.' +
'';
}
$("#scmBody").html(
'
' + body +
'' +
'
');
}
//Reopen the enclosing checkout as the project, so its history is in scope
function openOuterRepositoryAsProject(){
if (csGitOuterRoot == "") return;
openProjectFolder([{
filename: csGitOuterRoot.split("/").filter(Boolean).pop(),
filepath: csGitOuterRoot
}]);
}
function initRepository(){
if (!currentProjectFolder) return;
//Creating a repository inside another one is legal but rarely intended
if (csGitOuterRoot != "" &&
!confirm("This folder is inside the repository at:\n" + csGitOuterRoot +
"\n\nCreating a repository here nests one inside the other. Continue?")){
return;
}
gitcall("init", {}, function(response){
if (!response.success){
alert(response.error || "Unable to create the repository");
return;
}
csGitOuterRoot = "";
setStatusMessage("check", "Repository created");
refreshGitStatus();
});
}
/* ═══════════════════════════════════════════════════════════════════
Rendering
═══════════════════════════════════════════════════════════════════ */
var CS_GIT_BADGE = {
modified: "M",
added: "A",
deleted: "D",
renamed: "R",
copied: "C",
untracked: "U",
conflicted: "!"
};
function gitChangeRow(change, staged){
var filename = change.path.split("/").pop();
var folder = change.path.split("/").slice(0, -1).join("/");
var badge = CS_GIT_BADGE[change.status] || "?";
var encodedPath = encodeURIComponent(change.path);
var buttons =
'' +
'';
if (staged){
buttons += '' +
'';
} else {
buttons += '' +
'' +
'' +
'';
}
return '