//
// aegis - project change supervisor
// Copyright (C) 2002-2008 Peter Miller
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see
// .
//
#include
#include
#include
#include
#include
#include
#include
#include
struct complete_project_file_ty
{
complete_ty inherited;
change::pointer cp;
int baserel;
int usage_mask;
};
static void
destructor(complete_ty *cp)
{
complete_project_file_ty *this_thing;
this_thing = (complete_project_file_ty *)cp;
change_free(this_thing->cp);
}
static void
perform(complete_ty *cp, shell_ty *sh)
{
complete_project_file_ty *this_thing;
string_ty *prefix;
size_t j;
string_ty *base = 0;
//
// We need to figure the base of the file names, in case the user
// is completing their project file name from within a directory,
// and we must give answers strictly in that context.
//
this_thing = (complete_project_file_ty *)cp;
if (this_thing->baserel)
base = str_from_c("");
else
{
string_list_ty search_path;
string_ty *cwd;
string_ty *tmp;
change_search_path_get(this_thing->cp, &search_path, 1);
os_become_orig();
cwd = os_curdir();
os_become_undo();
for (j = 0; j < search_path.nstrings; ++j)
{
tmp = os_below_dir(search_path.string[j], cwd);
if (tmp)
{
if (tmp->str_length)
{
base = str_format("%s/", tmp->str_text);
str_free(tmp);
}
else
base = tmp;
break;
}
}
if (j >= search_path.nstrings)
{
//
// They are in a weird place, assume base relative.
//
base = str_from_c("");
}
str_free(cwd);
}
//
// Troll the complete list of project files.
//
string_list_ty candidate;
prefix = str_catenate(base, shell_prefix_get(sh));
for (j = 0; ; ++j)
{
fstate_src_ty *src;
string_ty *relfn;
src = this_thing->cp->pp->file_nth(j, view_path_simple);
if (!src)
break;
//
// Ignore files that don't match the prefix.
//
if (!str_leading_prefix(src->file_name, prefix))
continue;
//
// Ignore change files.
//
if (change_file_find(this_thing->cp, src->file_name, view_path_first))
continue;
//
// Ignore files that don't fit the profile.
//
if (!(this_thing->usage_mask & (1 << src->usage)))
continue;
//
// We have a completion candidate.
// Remove the base portion before emitting
//
relfn =
str_n_from_c
(
src->file_name->str_text + base->str_length,
src->file_name->str_length - base->str_length
);
candidate.push_back(relfn);
str_free(relfn);
}
//
// Now scan the change files.
//
for (j = 0; ; ++j)
{
fstate_src_ty *src;
string_ty *relfn;
src = change_file_nth(this_thing->cp, j, view_path_first);
if (!src)
break;
//
// Ignore files that aren't there.
//
switch (src->action)
{
case file_action_create:
case file_action_modify:
break;
case file_action_remove:
continue;
case file_action_insulate:
case file_action_transparent:
break;
}
//
// Ignore files that don't match the prefix.
//
if (!str_leading_prefix(src->file_name, prefix))
continue;
//
// Ignore files that don't fit the profile.
//
if (!(this_thing->usage_mask & (1 << src->usage)))
continue;
//
// We have a completion candidate.
// Remove the base portion before emitting
//
relfn =
str_n_from_c
(
src->file_name->str_text + base->str_length,
src->file_name->str_length - base->str_length
);
candidate.push_back(relfn);
str_free(relfn);
}
//
// Emit the list of files.
//
shell_emit_file_list(sh, &candidate);
}
static complete_vtbl_ty vtbl =
{
destructor,
perform,
sizeof(complete_project_file_ty),
"project file union",
};
complete_ty *
complete_project_file_union(change::pointer cp, int baserel, int usage_mask)
{
complete_ty *result;
complete_project_file_ty *this_thing;
result = complete_new(&vtbl);
this_thing = (complete_project_file_ty *)result;
this_thing->cp = cp;
this_thing->baserel = !!baserel;
this_thing->usage_mask = usage_mask;
return result;
}