ide: clang-format integration

This commit is contained in:
Mirek Fidler 2023-02-01 15:27:24 +01:00
parent 87034d3fe0
commit 2e77d71f12
19 changed files with 698 additions and 90 deletions

24
.clang-format Normal file
View file

@ -0,0 +1,24 @@
# .clang-format file for U++ framework
---
BasedOnStyle: LLVM
UseTab: AlignWithSpaces
IndentWidth: 4
TabWidth: 4
ColumnLimit: 96
---
Language: Cpp
AccessModifierOffset: -4
AllowShortFunctionsOnASingleLine: All
AlwaysBreakTemplateDeclarations: true
BreakBeforeBraces: Stroustrup
BreakConstructorInitializers: BeforeComma
CompactNamespaces: true
DerivePointerAlignment: false
IfMacros: ['ONCELOCK']
PointerAlignment: Left
SpaceBeforeParens: Custom
SpaceBeforeParensOptions:
AfterControlStatements: false
IndentAccessModifiers: false
IndentPPDirectives: None

View file

@ -12,7 +12,7 @@ AskContinue()
uname=`uname`
if [ -x "$(command -v apt-get)" ]; then
DEP="apt-get install g++ clang git make libgtk-3-dev libnotify-dev libbz2-dev libssl-dev xdotool"
DEP="apt-get install g++ clang git make libgtk-3-dev libnotify-dev libbz2-dev libssl-dev xdotool clang-format"
elif [ -x "$(command -v yum)" ]; then
DEP="yum install gcc-c++ clang git make gtk3-devel libnotify-devel bzip2-devel freetype-devel openssl-devel"
elif [ -x "$(command -v dnf)" ]; then

View file

@ -345,7 +345,7 @@ bool LocalProcess::DoStart(const char *command, const Vector<String> *arg, bool
execv(app_full, args.Begin());
LLOG("execve failed, errno = " << errno);
// printf("Error running '%s', error code %d\n", command, errno);
exit(-errno);
abort(); // do not use exit here: it calls global destructors...
return true;
#endif
}

View file

@ -38,7 +38,8 @@ bool AndroidManifest::Parse()
p.Skip();
}
} catch(const XmlError& e) {
}
catch(const XmlError& e) {
Loge() << METHOD_NAME << "Failed to parse manifest file with error \"" + e + "\".";
return false;
}

View file

@ -102,9 +102,9 @@ void MakeBuild::CreateHost(Host& host, const String& method, bool darkmode, bool
VectorMap<String, String> env = clone(Environment());
host.exedirs = SplitDirs(bm.Get("PATH", "") + ';' + env.Get("PATH", ""));
#ifdef PLATFORM_WIN32
String p = GetExeDirFile("bin/mingit/cmd");
if(FileExists(p + "/git.exe"))
host.exedirs.Add(p);
host.AddExecutable(GetExeDirFile("bin/mingit/cmd"), "git.exe");
host.AddExecutable(GetExeDirFile("bin/llvm/bin"), "clang-format.exe");
env.GetAdd("PATH") = Join(host.exedirs, ";");
#else
env.GetAdd("PATH") = Join(host.exedirs, ":");

View file

@ -10,25 +10,6 @@ String LocalPath(const String& filename)
return AppendFileName(GetLocalDir(), filename);
}
Vector<String> IgnoreList()
{
Vector<String> ignore;
const Workspace& wspc = GetIdeWorkspace();
for(int i = 0; i < wspc.GetCount(); i++) {
const Package& pk = wspc.GetPackage(i);
for(int j = 0; j < pk.GetCount(); j++)
if(!pk[j].separator && pk[j] == "ignorelist") {
FileIn in(SourcePath(wspc[i], pk[j]));
while(in && !in.IsEof()) {
String s = in.GetLine();
if(!s.IsEmpty())
ignore.Add(s);
}
}
}
return ignore;
}
String FollowCygwinSymlink(const String& file) {
for(String fn = file;;) {
if(fn.IsEmpty())

View file

@ -365,8 +365,6 @@ String GetPackagePathNest(const String& path);
String GetLocalDir();
String LocalPath(const String& filename);
Vector<String> IgnoreList();
bool IsFullDirectory(const String& d);
bool IsFolder(const String& path);

View file

@ -1,9 +1,10 @@
#include "Core.h"
#define LLOG(x)
#include <plugin/bz2/bz2.h>
#define LLOG(x)
#define METHOD_NAME "Host::" << UPP_FUNCTION_NAME << "(): "
Host::Host()
{
}
@ -381,6 +382,17 @@ const Vector<String>& Host::GetExecutablesDirs() const
return exedirs;
}
void Host::AddExecutable(const String& dir, const String& exe)
{
String p = dir + DIR_SEPS + exe;
if(!FileExists(p)) {
Loge() << METHOD_NAME << "Following executable file \"" << p << "\" doesn't exists.";
return;
}
exedirs.Add(dir);
}
bool Host::HasPlatformFlag(const Index<String>& cfg)
{
static const Index<String> platformFlags = {

View file

@ -45,6 +45,7 @@ struct Host {
void AddFlags(Index<String>& cfg);
const Vector<String>& GetExecutablesDirs() const;
void AddExecutable(const String& dir, const String& exe);
private:
bool HasPlatformFlag(const Index<String>& cfg);

View file

@ -27,7 +27,7 @@ void Ide::FormatJSON_XML(bool xml)
{
int l, h;
bool sel = editor.GetSelection(l, h);
if((sel ? h - l : editor.GetLength()) > 75*1024*1024) {
if((sel ? h - l : editor.GetLength()) > 75 * 1024 * 1024) {
Exclamation("Too big to reformat");
return;
}
@ -51,28 +51,588 @@ void Ide::FormatJSON_XML(bool xml)
}
}
void Ide::FormatJSON()
void Ide::FormatJSON() { FormatJSON_XML(false); }
void Ide::FormatXML() { FormatJSON_XML(true); }
String Ide::FindClangFormatPath()
{
FormatJSON_XML(false);
String p;
auto Check = [&](const String& dir) {
for(String fn : { ".clang-format", "_clang-format" }) {
p = AppendFileName(dir, fn);
if(FileExists(p))
return true;
}
return false;
};
for(String dir = GetFileFolder(editfile); dir.GetCount() > 3; dir = GetFileFolder(dir))
if(Check(dir))
return p;
for(String dir : GetUppDirs())
if(Check(dir))
return p;
return Null;
}
void Ide::FormatXML()
String ClangFormatPath()
{
FormatJSON_XML(true);
return ConfigFile("clang_format");
}
void Ide::FormatJSON_XML_File(bool xml)
VectorMap<String, String> ReadClangFormatFile(Stream& in)
{
if(IsNull(editfile))
return;
if(GetFileLength(editfile) >= 75*1024*1024)
Exclamation("Too big to reformat");
SaveFile();
String text = LoadFile(editfile);
if(!ReFormatJSON_XML(text, xml))
return;
if(PromptYesNo("Overwrite \1" + editfile + "\1 with reformated " + (xml ? "XML" : "JSON") + "?")) {
Upp::SaveFile(editfile, text);
EditAsText();
VectorMap<String, String> val;
String master_id;
while(!in.IsEof()) {
String l = in.GetLine();
String id;
bool nested = findarg(*l, ' ', '\t') >= 0;
CParser p(l);
try {
if(p.IsId()) {
String id = p.ReadId();
if(nested)
id = master_id + ":" + id;
else
master_id = id;
p.PassChar(':');
String value = TrimBoth(p.GetPtr());
int q = value.Find('#');
if(q >= 0)
value.Trim(q);
value = TrimBoth(value);
if(value.GetCount())
val.GetAdd(id) = value;
}
}
catch(CParser::Error) {
continue;
}
}
return val;
}
String ReformatCpp(CodeEditor& editor, bool setcursor)
{
String clang_format_path = ClangFormatPath();
FileIn in(clang_format_path);
VectorMap<String, String> fv = ReadClangFormatFile(in);
if(IsNull(fv.Get("BasedOnStyle", Null)))
clang_format_path = TheIde()->FindClangFormatPath();
int64 l, h;
bool sel = editor.GetSelection(l, h);
String cmd = "clang-format ";
if(sel) {
l = editor.GetLine(l) + 1;
h = editor.GetLine(h) + 1;
cmd << "--lines=" << l << ":" << h << " ";
}
String temp_path = CacheFile(AsString(Random()) + AsString(Random()) + "_to_format.cpp");
{
FileOut out(temp_path);
editor.Save(out, CHARSET_UTF8, TextCtrl::LE_LF);
if(out.IsError()) {
Exclamation("Failed to save temporary file \1" + temp_path);
return "Failed to save temporary file " + temp_path;
}
}
cmd << "\"--style=file:" << clang_format_path << "\" ";
String r;
int code = Sys(cmd + temp_path, r);
DeleteFile(temp_path);
if(code) {
if(code < 0)
return "Failed to start clang-format";
StringStream ss(r);
String l;
while(!ss.IsEof() && IsNull(l))
l = ss.GetLine();
int q = l.Find("error:");
if(q >= 0 && q < r.GetCount() - 2)
return TrimLeft(l.Mid(q + 6));
return Nvl(l, "Unspecified error.");
}
Vector<String> ln = Split(r, '\n', false);
for(String& s : ln)
s.TrimEnd("\r");
int n = editor.GetLineCount();
l = h = n;
for(int i = 0; i < n; i++)
if(i >= ln.GetCount() || editor.GetUtf8Line(i) != ln[i]) {
l = i;
break;
}
for(int i = 0; i < n; i++)
if(i >= ln.GetCount() || editor.GetUtf8Line(n - 1 - i) != ln[ln.GetCount() - 1 - i]) {
h = i;
break;
}
if(l + h >= n)
return Null;
editor.NextUndo();
int from = editor.GetPos(l);
editor.Remove(from, editor.GetPos(editor.GetLineCount() - h) - from);
ln.Remove(0, l);
ln.Trim(ln.GetCount() - h);
int pos = editor.Insert(from, Join(ln, "\n") + "\n", CHARSET_UTF8);
if(setcursor)
editor.SetCursor(pos);
return Null;
}
struct ClangFormat {
const char *id;
const char *type;
}
clang_format[] = {
{ "AccessModifierOffset", "@" }, // int
{ "AlignAfterOpenBracket", "Align:DontAlign:AlwaysBreak:BlockIndent" },
{ "AlignArrayOfStructures", "Left:Right:None" },
{ "AlignConsecutiveAssignments", "None:Consecutive:AcrossEmptyLines:AcrossComments:AcrossEmptyLinesAndComments" },
{ "AlignConsecutiveBitFields", "None:Consecutive:AcrossEmptyLines:AcrossComments:AcrossEmptyLinesAndComments" },
{ "AlignConsecutiveDeclarations", "None:Consecutive:AcrossEmptyLines:AcrossComments:AcrossEmptyLinesAndComments" },
{ "AlignConsecutiveMacros", "None:Consecutive:AcrossEmptyLines:AcrossComments:AcrossEmptyLinesAndComments" },
{ "AlignEscapedNewlines", "DontAlign:Left:Right" },
{ "AlignOperands", "DontAlign:Align:AlignAfterOperator" },
{ "AlignTrailingComments", "!" }, // bool
{ "AllowAllArgumentsOnNextLine", "!" },
{ "AllowAllConstructorInitializersOnNextLine", "!" },
{ "AllowAllParametersOfDeclarationOnNextLine", "!" },
{ "AllowShortBlocksOnASingleLine", "Never:Empty:Always" },
{ "AllowShortCaseLabelsOnASingleLine", "!" },
{ "AllowShortEnumsOnASingleLine", "!" },
{ "AllowShortFunctionsOnASingleLine", "None:InlineOnly:Empty:Inline:All" },
{ "AllowShortIfStatementsOnASingleLine", "Never:WithoutElse:OnlyFirstIf:AllIfsAndElse" },
{ "AllowShortLambdasOnASingleLine", "None:Empty:Inline:All" },
{ "AllowShortLoopsOnASingleLine", "!" },
{ "AlwaysBreakAfterDefinitionReturnType", "None:All:TopLevel" },
{ "AlwaysBreakAfterReturnType", "None:All:TopLevel:AllDefinitions:TopLevelDefinitions" },
{ "AlwaysBreakBeforeMultilineStrings", "!" },
{ "AlwaysBreakTemplateDeclarations", "No:MultiLine:Yes" },
{ "BinPackArguments", "!" },
{ "BinPackParameters", "!" },
{ "BitFieldColonSpacing", "Both:None:Before:After" },
{ "BraceWrapping", "" },
{ " AfterCaseLabel", "!" },
{ " AfterControlStatement", "Never:MultiLine:Always" },
{ " AfterEnum","!" },
{ " AfterFunction","!" },
{ " AfterNamespace","!" },
{ " AfterObjCDeclaration","!" },
{ " AfterStruct","!" },
{ " AfterUnion","!" },
{ " AfterExternBlock","!" },
{ " BeforeCatch","!" },
{ " BeforeElse","!" },
{ " BeforeLambdaBody","!" },
{ " BeforeWhile","!" },
{ " IndentBraces","!" },
{ " SplitEmptyFunction","!" },
{ " SplitEmptyRecord","!" },
{ " SplitEmptyNamespace","!" },
{ "BreakAfterAttributes", "Always:Leave:Never" },
{ "BreakBeforeBinaryOperators", "None:NonAssignment:All" },
{ "BreakBeforeBraces", "Attach:Linux:Mozilla:Stroustrup:Allman:Whitesmiths:GNU:WebKit:Custom" },
{ "BreakBeforeConceptDeclarations", "Never:Allowed:Always" },
{ "BreakBeforeInlineASMColon", "Never:OnlyMultiline:Always" },
{ "BreakBeforeTernaryOperators", "!" },
{ "BreakConstructorInitializers", "BeforeColon:BeforeComma:AfterColon" },
{ "BreakInheritanceList", "BeforeColon:BeforeComma:AfterColon:AfterComma" },
{ "BreakStringLiterals", "!" },
{ "ColumnLimit", "#" }, // unsigned
{ "CompactNamespaces", "!" },
{ "ConstructorInitializerIndentWidth", "#" },
{ "ContinuationIndentWidth", "#" },
{ "Cpp11BracedListStyle", "!" },
{ "DeriveLineEnding", "!" },
{ "DerivePointerAlignment", "!" },
{ "DisableFormat", "!" },
{ "EmptyLineAfterAccessModifier", "Never:Leave:Always" },
{ "EmptyLineBeforeAccessModifier", "Never:Leave:LogicalBlock:Always" },
{ "ExperimentalAutoDetectBinPacking", "!" },
{ "FixNamespaceComments", "!" },
{ "IndentAccessModifiers", "!" },
{ "IndentCaseBlocks", "!" },
{ "IndentCaseLabels", "!" },
{ "IndentExternBlock", "AfterExternBlock:NoIndent:Indent" },
{ "IndentGotoLabels", "!" },
{ "IndentPPDirectives", "None:AfterHash:BeforeHash" },
{ "IndentRequiresClause", "!" },
{ "IndentWidth", "#" },
{ "IndentWrappedFunctionNames", "!" },
{ "InsertBraces", "!" },
{ "InsertNewlineAtEOF", "!" },
{ "InsertTrailingCommas", "None:Wrapped" },
{ "IntegerLiteralSeparator", "" },
{ " Decimal", "@" },
{ " Hex", "@" },
{ " Binary", "@" },
{ "KeepEmptyLinesAtTheStartOfBlocks", "!" },
{ "LambdaBodyIndentation", "Signature:OuterScope" },
{ "MaxEmptyLinesToKeep", "#" },
{ "NamespaceIndentation", "None:Inner:All" },
{ "PPIndentWidth", "@" },
{ "PackConstructorInitializers", "Never:BinPack:CurrentLine:NextLine" },
{ "PenaltyBreakAssignment", "#" },
{ "PenaltyBreakBeforeFirstCallParameter", "#" },
{ "PenaltyBreakComment", "#" },
{ "PenaltyBreakFirstLessLess", "#" },
{ "PenaltyBreakOpenParenthesis", "#" },
{ "PenaltyBreakString", "#" },
{ "PenaltyBreakTemplateDeclaration", "#" },
{ "PenaltyExcessCharacter", "#" },
{ "PenaltyIndentedWhitespace", "#" },
{ "PenaltyReturnTypeOnItsOwnLine", "#" },
{ "PointerAlignment", "Left:Right:Middle" },
{ "QualifierAlignment", "Leave:Left:Right:Custom" },
{ "ReferenceAlignment", "Pointer:Left:Right:Middle" },
{ "ReflowComments", "!" },
{ "RemoveBracesLLVM", "!" },
{ "RemoveSemicolon", "!" },
{ "RequiresClausePosition", "OwnLine:WithPreceding:WithFollowing:SingleLine" },
{ "RequiresExpressionIndentation", "OuterScope:Keyword" },
{ "SeparateDefinitionBlocks", "Leave:Always:Never" },
{ "ShortNamespaceLines", "#" },
{ "SortIncludes", "Never:CaseSensitive:CaseInsensitive" },
{ "SortUsingDeclarations", "Never:Lexicographic:LexicographicNumeric" },
{ "SpaceAfterCStyleCast", "!" },
{ "SpaceAfterLogicalNot", "!" },
{ "SpaceAfterTemplateKeyword", "!" },
{ "SpaceAroundPointerQualifiers", "Default:Before:After:Both" },
{ "SpaceBeforeAssignmentOperators", "!" },
{ "SpaceBeforeCaseColon", "!" },
{ "SpaceBeforeCpp11BracedList", "!" },
{ "SpaceBeforeCtorInitializerColon", "!" },
{ "SpaceBeforeInheritanceColon", "!" },
{ "SpaceBeforeParens", "Never:ControlStatements:ControlStatementsExceptControlMacros:NonEmptyParentheses:Always:Custom" },
{ "SpaceBeforeParensOptions", "" },
{ " AfterControlStatements", "!" },
{ " AfterForeachMacros", "!" },
{ " AfterFunctionDeclarationName", "!" },
{ " AfterFunctionDefinitionName", "!" },
{ " AfterIfMacros", "!" },
{ " AfterOverloadedOperator", "!" },
{ " AfterRequiresInClause", "!" },
{ " AfterRequiresInExpression", "!" },
{ " BeforeNonEmptyParentheses", "!" },
{ "SpaceBeforeRangeBasedForLoopColon", "!" },
{ "SpaceBeforeSquareBrackets", "!" },
{ "SpaceInEmptyBlock", "!" },
{ "SpaceInEmptyParentheses", "!" },
{ "SpacesBeforeTrailingComments", "#" },
{ "SpacesInAngles", "Never:Always:Leave" },
{ "SpacesInCStyleCastParentheses", "!" },
{ "SpacesInConditionalStatement", "!" },
{ "SpacesInContainerLiterals", "!" },
{ "SpacesInLineCommentPrefix", "" },
{ " Minimum", "#" },
{ " Maximum", "#" },
{ "SpacesInParentheses", "!" },
{ "SpacesInSquareBrackets", "!" },
{ "TabWidth", "#" },
{ "UseTab", "Never:ForIndentation:ForContinuationAndIndentation:AlignWithSpaces:Always" },
#ifdef _DEBUG
{ "Test", "Never:ForIndentation:ForContinuationAndIndentation:AlignWithSpaces:Always" },
#endif
};
struct ReformatDlg : WithReformatLayout<TopWindow> {
String editfile;
String code;
bool sel;
int l, h;
Array<Ctrl> option;
Array<Label> lbl;
ParentCtrl soptions;
int scy;
ScrollBar sb;
virtual void Layout() override;
virtual void MouseWheel(Point p, int zdelta, dword keyflags) override;
void Set(LineEdit& editor);
void Sync();
String Get();
void Set(Stream& in);
ReformatDlg();
~ReformatDlg();
};
ReformatDlg::ReformatDlg()
{
CtrlLayoutOKCancel(*this, "Reformat");
view.Highlight("cpp");
view.HideBar();
view.SetFont(CourierZ(12));
view.ShowSpaces();
view.ShowTabs();
view.SetReadOnly();
String p = TheIde()->FindClangFormatPath();
if(p.GetCount())
base.Add(Null, ".clang-format file " + p);
for(String id : { "LLVM", "Google", "Chromium", "Mozilla", "WebKit", "Microsoft", "GNU" })
base.Add("BasedOnStyle: " + id, "Based on style " + id);
base << [=] { Sync(); };
base.SetIndex(0);
int cy = EditField::GetStdHeight();
int y = 0;
int lw = 0;
for(const ClangFormat& f : clang_format)
if(f.type && *f.type != '!')
lw = max(lw, GetTextSize(f.id, StdFont().Bold()).cx + DPI(4) + (*f.id == ' ') * DPI(20));
for(const ClangFormat& f : clang_format) {
int x = 0;
String id = f.id;
if(*id == ' ') {
id = id.Mid(1);
x = DPI(20);
}
if(f.type && *f.type == '!') {
Option& o = option.Create<Option>();
o.ThreeState();
o.SetLabel(id);
o <<= Null;
o << [=] { Sync(); };
soptions << o.HSizePos(x, DPI(2)).TopPos(y, cy);
}
else {
Label& l = lbl.Create<Label>();
l.SetLabel(id);
soptions << l.LeftPos(x, Zx(200)).TopPos(y, cy);
if(f.type) {
if(*f.type == '#' || *f.type == '@') {
WithDropChoice<EditIntSpin>& e = option.Create<WithDropChoice<EditIntSpin>>();
e.MinMax(*f.type == '@' ? -100 : 0, 100);
for(int q = *f.type == '@' ? -8 : 0; q <= 8; q++)
e.AddList(q);
e.NullText("default");
e << [=] { Sync(); };
soptions << e.HSizePos(lw, DPI(2)).TopPos(y, cy);
}
else
if(*f.type) {
DropList& dl = option.Create<DropList>();
dl.Add(Null, AttrText("default").Italic().NormalInk(SCyan()));
for(const String& s : Split(f.type, ':'))
dl.Add(s);
dl << [=] { Sync(); };
soptions << dl.HSizePos(lw, DPI(2)).TopPos(y, cy);
}
}
}
y += cy + DPI(2);
}
sb.SetTotal(y);
options.SetFrame(ViewFrame());
options.AddFrame(sb);
options << soptions.HSizePos().TopPos(0, sb.GetTotal());
sb << [=] {
soptions.TopPos(-sb, sb.GetTotal());
};
save << [=] {
SelectSaveFile("All files\t*.*", Get());
};
load << [=] {
SelectFileIn in("All files\t*.*");
Set(in);
};
clear << [=] {
if(PromptYesNo("Set all options to default?")) {
for(Ctrl& q : option)
q <<= Null;
Sync();
}
};
FileIn in(ClangFormatPath());
Set(in);
}
ReformatDlg::~ReformatDlg()
{
Sync();
}
void ReformatDlg::MouseWheel(Point, int zdelta, dword)
{
sb.Wheel(zdelta, EditField::GetStdHeight() + DPI(2));
}
void ReformatDlg::Set(Stream& in)
{
VectorMap<String, String> val = ReadClangFormatFile(in);
String s = val.Get("BasedOnStyle", Null);
if(s.GetCount()) {
s = "BasedOnStyle: " + s;
if(base.HasKey(s))
base <<= s;
}
else
base.SetIndex(0);
int ii = 0;
String master_id;
for(const ClangFormat& f : clang_format) {
int x = 0;
String id = f.id;
if(*id == ' ')
id = master_id + ":" + TrimBoth(id);
else
master_id = id;
String v = val.Get(id, Null);
if(f.type && *f.type) {
Ctrl& o = option[ii++];
o <<= Null;
if(v.GetCount()) {
if(*f.type == '!')
o <<= decode(v, "true", true, "false", false, Null);
else
if(findarg(*f.type, '@', '#') >= 0)
o <<= StrInt(v);
else {
DropList *l = dynamic_cast<DropList *>(&o);
if(l && l->HasKey(v))
*l <<= v;
}
}
}
}
}
String ReformatDlg::Get()
{
String out;
out << "Language: Cpp\n";
out << ~base << "\n";
int ii = 0;
String master_id;
for(const ClangFormat& f : clang_format) {
String value;
if(f.type && *f.type) {
value = ~~option[ii++];
if(*f.type == '!')
value = decode(value, "1", "true", "0", "false", "");
}
else
master_id = f.id;
if(value.GetCount()) {
if(*f.id == ' ') {
if(master_id.GetCount()) {
out << master_id << ":\n";
master_id.Clear();
}
out << " ";
}
out << f.id << ": " << value << "\n";
}
}
return out;
}
void ReformatDlg::Layout()
{
sb.SetPage(options.GetSize().cy);
}
void ReformatDlg::Sync()
{
view.Set(code, CHARSET_UTF8);
view.ClearSelection();
if(sel)
view.SetSelection(l, h);
Upp::SaveFile(ClangFormatPath(), Get());
String err = ReformatCpp(view, false);
if(IsNull(err)) {
error.SetLabel("");
ok.Enable();
}
else {
error.SetLabel("Clang-format has failed: " + Filter(err, CharFilterNoCrLf));
ok.Disable();
}
for(Ctrl& q : option)
q.Enable(!IsNull(base));
for(Label& q : lbl)
q.SetInk(IsNull(base) ? SColorDisabled() : SColorText());
view.SetCursor(l);
int ii = 0;
int li = 0;
for(const ClangFormat& f : clang_format) {
if(f.type && *f.type == '!') {
Option *o = dynamic_cast<Option *>(&option[ii++]);
o->SetFont(IsNull(*o) ? StdFont() : StdFont().Bold());
}
else {
Label& l = lbl[li++];
if(f.type && *f.type) {
Ctrl& c = option[ii++];
l.SetFont(IsNull(c) ? StdFont() : StdFont().Bold());
}
}
}
}
void ReformatDlg::Set(LineEdit& editor)
{
sel = editor.GetSelection(l, h);
code = editor.Get(CHARSET_UTF8);
}
void Ide::ReformatCodeDlg()
{
ReformatDlg dlg;
dlg.editfile = editfile;
dlg.Set(editor);
dlg.Sync();
if(dlg.Execute() == IDOK) {
String error = ReformatCpp(editor, true);
if(error.GetCount())
PromptOK("clang-format has failed:&\1" + error);
}
}
void Ide::ReformatCode()
{
String clang_format_path = FindClangFormatPath();
if(IsNull(clang_format_path)) {
ReformatCodeDlg();
return;
}
if(ReformatCpp(editor, true).GetCount())
ReformatCodeDlg();
}
void Ide::ReformatComment() { editor.ReformatComment(); }

View file

@ -307,6 +307,7 @@ void Ide::EditorMenu(Bar& bar)
{
bar.Sub("Assist", [=](Bar& bar) { AssistMenu(bar); });
InsertAdvanced(bar);
Reformat(bar);
bar.MenuSeparator();
OnlineSearchMenu(bar);
bar.Add(IsClipboardAvailableText() && (editor.IsSelection() || editor.GetLength() < 1024*1024),

View file

@ -41,6 +41,7 @@ NewPackageFileWindow::NewPackageFileWindow()
Type("js", "JavaScript");
Type("py", "Python");
type.AddSeparator();
Type("clang-format", "ClangFormat configuration file");
Type("", "Other");
name << [=] {
@ -52,7 +53,6 @@ NewPackageFileWindow::NewPackageFileWindow()
Sync();
};
name <<= ".cpp";
type <<= "cpp";
type << [=] {
@ -75,8 +75,12 @@ String NewPackageFileWindow::GetError()
String p = AppendFileName(folder, n);
if(FileExists(p))
return String().Cat() << "File&[* \1" << p << "\1]&already exists!";
if(*n == '.')
return "Invalid filename!";
if(*n == '.') {
Index<String> exceptions = {".clang-format"};
if(exceptions.Find(n) == -1) {
return "Invalid filename!";
}
}
return Null;
}

View file

@ -648,7 +648,6 @@ public:
void FormatJSON_XML(bool xml);
void FormatJSON();
void FormatXML();
void FormatJSON_XML_File(bool xml);
bool browser_closeesc;
bool bookmark_pos;
@ -833,12 +832,19 @@ public:
void InsertMenu(Bar& bar);
void InsertInclude(Bar& bar);
void InsertAdvanced(Bar& bar);
void Reformat(Bar& bar);
void AssistEdit(Bar& menu);
void EditorMenu(Bar& bar);
void ToggleWordwrap();
void CopyPosition();
void GotoPosition();
void ReformatMenu(Bar& menu);
void ReformatCodeDlg();
void ReformatCode();
void ReformatComment();
String FindClangFormatPath();
void OnlineSearchMenu(Bar& menu);
@ -868,7 +874,6 @@ public:
void ToComment();
void CommentLines();
void UnComment();
void ReformatComment();
void MacroMenu(Bar& menu);
bool HasMacros();

View file

@ -38,10 +38,6 @@ KEY(LINEENDINGS, "Remove trailing tabs and spaces", 0)
KEY(DUPLICATEIT, "Duplicate line or selection", K_CTRL_D)
KEY(WORDWRAP, "Word wrap", K_ALT_W)
KEY(FORMATCODE, "Format code in editor", 0)
KEY(FORMATJSON, "Reformat JSON in editor", 0)
KEY(FORMATXML, "Reformat XML in editor", 0)
KEY(ORGANIZER, "Package organizer..", 0)
KEY(CUSTOM, "Custom build steps..", 0)
KEY(MAINCONFIG, "Main package configuration..", 0)
@ -105,8 +101,6 @@ KEY(SWAPS, "Go to definition/declaration", K_ALT_I)
KEY(IDUSAGE, "Usage", K_ALT_U)
KEY(USAGE, "Usage of current function", K_SHIFT|K_ALT_U)
KEY(JUMPS, "Context go to", K_ALT_J)
KEY(CLEARMARKERSFILE, "Remove change markers in file", K_ALT_R)
KEY(CLEARMARKERSALL, "Remove all change markers", K_SHIFT|K_ALT_R)
KEY(TOGGLEINDEX, "File index", K_CTRL_F12)
KEY(SEARCHINDEX, "File index search", K_F12)
KEY(COMPLETE, "Complete identifier", K_CTRL_COMMA)
@ -120,7 +114,6 @@ KEY(TOCSTRING, "Convert to C string", 0)
KEY(TOCOMMENT, "Comment code", K_ALT_K)
KEY(COMMENTLINES, "Comment code lines", K_SHIFT|K_ALT_K)
KEY(UNCOMMENT, "Uncomment code", K_CTRL_K|K_ALT_K)
KEY(REFORMAT_COMMENT, "Reformat comment paragraph", K_ALT_R)
KEY(DIFF, "File..", 0)
KEY(DIFFLOG, "Log..", 0)
@ -128,8 +121,11 @@ KEY(SVNDIFF, "Show repository history of file..", 0)
KEY(PATCH, "Display/apply patch..", 0)
KEY(DIRDIFF, "Compare directories..", 0)
KEY(REFORMAT_JSON, "Reformat JSON file", 0);
KEY(REFORMAT_XML, "Reformat XML file", 0);
KEY(REFORMAT_CODE, "Reformat code", K_ALT_R)
KEY(REFORMAT_CODE2, "Reformat code with options..", K_SHIFT|K_ALT_R)
KEY(REFORMAT_JSON, "Reformat JSON", 0)
KEY(REFORMAT_XML, "Reformat XML", 0)
KEY(REFORMAT_COMMENT, "Reformat comment paragraph", K_SHIFT|K_ALT_P)
KEY(RESCANCURRENTFILE, "Rescan current file", 0)

View file

@ -907,3 +907,15 @@ LAYOUT(UppHubSettingsLayout, 544, 64)
ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).RightPosZ(8, 64).BottomPosZ(8, 24))
END_LAYOUT
LAYOUT(ReformatLayout, 1024, 724)
ITEM(Upp::DropList, base, LeftPosZ(4, 360).TopPosZ(8, 19))
ITEM(Upp::ParentCtrl, options, LeftPosZ(4, 360).TopPosZ(32, 652))
ITEM(CodeEditor, view, LeftPosZ(368, 652).TopPosZ(8, 676))
ITEM(Upp::Button, save, SetLabel(t_("Save..")).RightPosZ(956, 64).BottomPosZ(8, 24))
ITEM(Upp::Button, load, SetLabel(t_("Load..")).RightPosZ(888, 64).BottomPosZ(8, 24))
ITEM(Upp::Button, clear, SetLabel(t_("Clear")).RightPosZ(820, 64).BottomPosZ(8, 24))
ITEM(Upp::Label, error, SetLabel(t_("error")).SetAlign(Upp::ALIGN_CENTER).SetFont(Upp::StdFont().Bold()).SetInk(Upp::SRed).LeftPosZ(216, 656).TopPosZ(692, 24))
ITEM(Upp::Button, ok, SetLabel(t_("OK")).RightPosZ(72, 64).BottomPosZ(8, 24))
ITEM(Upp::Button, cancel, SetLabel(t_("Cancel")).RightPosZ(4, 64).BottomPosZ(8, 24))
END_LAYOUT

View file

@ -28,13 +28,13 @@ file
ide.h options(BUILDER_OPTION) PCH,
version.h,
UppDlg.h,
ide.key,
BaseDlg.cpp,
SelectPkg.cpp,
UppWspc.cpp,
NewPackageFile.cpp,
Organizer.cpp,
Template.cpp,
ide.key,
Console.cpp,
FindFile.cpp,
FindInFiles.cpp,

View file

@ -127,6 +127,12 @@ void Ide::InsertAdvanced(Bar& bar)
bar.Add(b, "Advanced", THISBACK(EditSpecial));
}
void Ide::Reformat(Bar& bar)
{
bool b = !editor.IsReadOnly();
bar.Sub(b, "Reformat", [=] (Bar& menu) { ReformatMenu(menu); });
}
void Ide::EditSpecial(Bar& menu)
{
bool b = !editor.IsReadOnly();
@ -149,10 +155,6 @@ void Ide::EditSpecial(Bar& menu)
.Help("Copy the current identifier to the clipboard");
menu.Add(b, AK_DUPLICATEIT, THISBACK(Duplicate))
.Help("Duplicate the current line");
menu.Add(b, AK_FORMATJSON, THISBACK(FormatJSON))
.Help("Reformat JSON");
menu.Add(b, AK_FORMATXML, THISBACK(FormatXML))
.Help("Reformat XML");
menu.Add(b && editor.IsSelection(), AK_TOUPPER, THISBACK(TextToUpper))
.Help("Convert letters in selection to uppercase");
menu.Add(b && editor.IsSelection(), AK_TOLOWER, THISBACK(TextToLower))
@ -171,8 +173,6 @@ void Ide::EditSpecial(Bar& menu)
.Help("Comment code lines");
menu.Add(b && editor.IsSelection(), AK_UNCOMMENT, THISBACK(UnComment))
.Help("Uncomment code");
menu.Add(b, AK_REFORMAT_COMMENT, THISBACK(ReformatComment))
.Help("Reformat multiline comment into paragraph");
menu.Add(b, "Remove debugging logs (DDUMP...)", [=] { RemoveDs(); });
menu.MenuSeparator();
menu.Add(AK_COPY_POSITION, [=] { CopyPosition(); });
@ -283,8 +283,27 @@ void Ide::Edit(Bar& menu)
menu.Add("Find and Replace", THISBACK(SearchMenu));
if(!designer && menu.IsMenuBar())
if(!designer && menu.IsMenuBar()) {
InsertAdvanced(menu);
Reformat(menu);
}
}
void Ide::ReformatMenu(Bar& menu)
{
bool b = !editor.IsReadOnly();
menu.Add(b, AK_REFORMAT_CODE, [=] { ReformatCode(); })
.Help("Reformat current file with clang-format");
menu.Add(b, AK_REFORMAT_CODE2, [=] { ReformatCodeDlg(); });
menu.Separator();
menu.Add(b, AK_REFORMAT_JSON, [=] { FormatJSON(); })
.Help("Reformat JSON");
menu.Add(b, AK_REFORMAT_XML, [=] { FormatXML(); })
.Help("Reformat XML");
menu.Separator();
menu.Add(b, AK_REFORMAT_COMMENT, [=] { ReformatComment(); })
.Help("Reformat multiline comment into paragraph");
}
bool Ide::HasMacros()
@ -772,6 +791,7 @@ void Ide::BrowseMenu(Bar& menu)
AssistMenu(menu);
menu.Add(!designer, AK_GO_TO_LINE, THISBACK(GoToLine));
AssistEdit(menu);
Reformat(menu);
menu.MenuSeparator();
}
@ -804,8 +824,6 @@ void Ide::BrowseMenu(Bar& menu)
menu.AddMenu(AK_QTF, IdeCommonImg::Qtf(), THISBACK(Qtf));
menu.AddMenu(!designer, AK_XML, IdeCommonImg::xml(), THISBACK(Xml));
menu.AddMenu(!designer, AK_JSON, IdeCommonImg::json(), THISBACK(Json));
menu.Add(AK_REFORMAT_JSON, [=] { FormatJSON_XML_File(false); });
menu.Add(AK_REFORMAT_XML, [=] { FormatJSON_XML_File(true); });
menu.AddMenu(!designer, AK_ASERRORS, IdeImg::errors(), THISBACK(AsErrors));
menu.AddMenu(AK_DIRDIFF, DiffImg::DirDiff(), THISBACK(DoDirDiff));
menu.AddMenu(AK_PATCH, DiffImg::PatchDiff(), THISBACK(DoPatchDiff));

View file

@ -386,11 +386,6 @@ void Ide::UnComment()
AlterText(sUncomment);
}
void Ide::ReformatComment()
{
editor.ReformatComment();
}
void Ide::Times()
{
WithStatisticsLayout<TopWindow> statdlg;

View file

@ -1,18 +1,18 @@
LAYOUT(SpinLayout, 768, 500)
ITEM(EditIntSpin, int_1, LeftPosZ(12, 160).TopPosZ(12, 19))
ITEM(EditInt64Spin, int64_1, LeftPosZ(12, 160).TopPosZ(36, 19))
ITEM(EditDoubleSpin, double_1, LeftPosZ(12, 160).TopPosZ(60, 19))
ITEM(EditDateSpin, date_1, LeftPosZ(12, 160).TopPosZ(84, 19))
ITEM(EditTimeSpin, time_1, LeftPosZ(12, 160).TopPosZ(108, 19))
ITEM(EditIntSpin, int_2, LeftPosZ(188, 160).TopPosZ(12, 19))
ITEM(EditInt64Spin, int64_2, LeftPosZ(188, 160).TopPosZ(36, 19))
ITEM(EditDoubleSpin, double_2, LeftPosZ(188, 160).TopPosZ(60, 19))
ITEM(EditDateSpin, date_2, LeftPosZ(188, 160).TopPosZ(84, 19))
ITEM(EditTimeSpin, time_2, LeftPosZ(188, 160).TopPosZ(108, 19))
ITEM(EditIntSpin, int_3, LeftPosZ(364, 160).TopPosZ(12, 19))
ITEM(EditInt64Spin, int64_3, LeftPosZ(364, 160).TopPosZ(36, 19))
ITEM(EditDoubleSpin, double_3, LeftPosZ(364, 160).TopPosZ(60, 19))
ITEM(EditDateSpin, date_3, LeftPosZ(364, 160).TopPosZ(84, 19))
ITEM(EditTimeSpin, time_3, LeftPosZ(364, 160).TopPosZ(108, 19))
ITEM(Upp::EditIntSpin, int_1, LeftPosZ(12, 160).TopPosZ(12, 19))
ITEM(Upp::EditInt64Spin, int64_1, LeftPosZ(12, 160).TopPosZ(36, 19))
ITEM(Upp::EditDoubleSpin, double_1, LeftPosZ(12, 160).TopPosZ(60, 19))
ITEM(Upp::EditDateSpin, date_1, LeftPosZ(12, 160).TopPosZ(84, 19))
ITEM(Upp::EditTimeSpin, time_1, LeftPosZ(12, 160).TopPosZ(108, 19))
ITEM(Upp::EditIntSpin, int_2, LeftPosZ(188, 160).TopPosZ(12, 19))
ITEM(Upp::EditInt64Spin, int64_2, LeftPosZ(188, 160).TopPosZ(36, 19))
ITEM(Upp::EditDoubleSpin, double_2, LeftPosZ(188, 160).TopPosZ(60, 19))
ITEM(Upp::EditDateSpin, date_2, LeftPosZ(188, 160).TopPosZ(84, 19))
ITEM(Upp::EditTimeSpin, time_2, LeftPosZ(188, 160).TopPosZ(108, 19))
ITEM(Upp::EditIntSpin, int_3, LeftPosZ(364, 160).TopPosZ(12, 19))
ITEM(Upp::EditInt64Spin, int64_3, LeftPosZ(364, 160).TopPosZ(36, 19))
ITEM(Upp::EditDoubleSpin, double_3, LeftPosZ(364, 160).TopPosZ(60, 19))
ITEM(Upp::EditDateSpin, date_3, LeftPosZ(364, 160).TopPosZ(84, 19))
ITEM(Upp::EditTimeSpin, time_3, LeftPosZ(364, 160).TopPosZ(108, 19))
END_LAYOUT