This is my first post on stack overflow, so please forgive me for any mistakes.
I learned c++ with Xcode and recently started working with a group that uses Emacs. This group has a huge code in c++ and so I did a CMake interface to generate a project in Xcode. What happened is that the code appears badly indented in Xcode. For instance, these lines in emacs:
if ( argc > 4 ) {
std::string argument( argv[arg_index++] );
// NOTE: file_name should NOT be "aboveCrack" or "belowCrack"
if ( argument == "aboveCrack" ) {
surf_to_draw = CrackMn3DGraphDX2::EAboveSurface;
}
else if ( argument == "belowCrack" ) {
surf_to_draw = CrackMn3DGraphDX2::EBelowSurface;
}
else {
// argument 4 is comp. crack surface output name
got_file_name = true;
postCompSurface_file_name = argument;
}
}
if ( !got_file_name && argc > 5 ) {
got_file_name = true;
postCompSurface_file_name = argv[arg_index++];
if ( argc > 6 ) {
// get comp. crack surface output style
postCompSurface_style = argv[arg_index++];
}
}
Look like this in Xcode:
if ( argc > 4 ) {
std::string argument( argv[arg_index++] );
// NOTE: file_name should NOT be "aboveCrack" or "belowCrack"
if ( argument == "aboveCrack" ) {
surf_to_draw = CrackMn3DGraphDX2::EAboveSurface;
}
else if ( argument == "belowCrack" ) {
surf_to_draw = CrackMn3DGraphDX2::EBelowSurface;
}
else {
// argument 4 is comp. crack surface output name
got_file_name = true;
postCompSurface_file_name = argument;
}
}
if ( !got_file_name && argc > 5 ) {
got_file_name = true;
postCompSurface_file_name = argv[arg_index++];
if ( argc > 6 ) {
// get comp. crack surface output style
postCompSurface_style = argv[arg_index++];
}
}
Which is impossible to program with.
I searched and apparently it has something to do with the tabs in Emacs. Based on this, one fix I could find was to open each file in Emacs and do C-x h (mark all) followed by M-x untabify. This transforms the tabs in spaces and everything looks good in Xcode.
The problems with this idea are that it requires to change the files one by one and it won't stop this from happening again in the future.
Therefore, my question is: is there a way to open the Emacs indented files in Xcode preserving the indentation?
Many thanks!
Nathan Shauer
The first setting that you need to put in your .emacs is: (setq-default indent-tabs-mode nil). This will make sure emacs uses spaces instead of tabs for indentation.
Also, I created a tiny function:
(defun rag/untabify-buffer ()
;; get rid of all the tabs in a buffer
(interactive)
(untabify (point-min) (point-max))
nil)
Add this to before-save-hook and this will make sure all the files will be untabified when you make a change and save a file. Once you've untabified all files, you can remove the hook
No. While it is possible to use emacs to make these changes or even a number of other tools which can automate such changes, it won't really fix your problem as you will likely have to do it every time you check out the code from version control. Depending on the version control system used, it is also possible that doing such formatting changes will result in the code appearing to be modified, which will result in larger checkins and make other useful tools less useful because more will appear to have been changed than was actually changed. This will likely frustrate other project members.
There are two basic approaches, but one depends on the version control solution being used by the project. The first solution is to get the project to agree on a coding standard which specifies either that normal spaces must be used for indentation or that tabs are to be used. The problems you are seeing are primarily due to a mix. Emacs is able to handle this sort of mixed formatting quite well, but other editors, like Xcode are not so smart.
The other approach, which can work quite well because it doesn't rely on everyone following the standard is to configure the version control system to translate tabs as part of the checkin process into spaces. How this is done depends on the version control system being used.
Essentially, this is a problem which needs to be addressed at the project or version control level. Anything you do will only need to be repeated every time you do a fresh pull from version control for any files which have been modified. Fix it at the repository level and the issue will go away.
Related
Using C++20 and std::filesystem::recursive_directory_iterator on macOS, this code:
for (auto& f : recursive_directory_iterator(getenv("HOME"), directory_options::skip_permission_denied)) {
// dummy
}
Which should, according to my understanding of the documentation, skip directories which it does not have permission to recurse into, encounters an error upon trying to recurse into ~/Library/Application Support/MobileSync/.
However:
in recursive_directory_iterator::operator++(): attempting recursion into "/Users/t/Library/Application Support/MobileSync": Operation not permitted
I assume this means that there is some permission / security feature in place that the iterator will not skip over even if skip_permission_denied is present - what might this be, and how would I cleanly make the iterator skip over directories that cause it to break regardless of permissions?
I could manually disable_recursion_pending() when encountering known directories like MobileSync or .Trash that cause this problem, but that would be a messy solution compared to being able to detect in advance when a directory will cause this issue.
I'm afraid there is no easy way around it, as the iterator is "closed" on error so a post-error disable_recursion_pending will not help. I opened an issue for libcxx (https://github.com/llvm/llvm-project/issues/48870) and libstdc++ (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99533) that got worked on, but the libcxx one was not fixed yet, and even then it would have to make it into macOS as on macOS the standard library is part of the system.
One admittedly ugly but possible non-hardcoded workaround would be to blacklist dynamically and retry e.g. somewhere along the lines of:
// ugly workaround to iterate the home dir on macOS with std::filesystem:
std::set<fs::path> blacklist;
while(true) {
fs::path lastPath;
try {
for(auto rdi = fs::recursive_directory_iterator(getenv("HOME"), fs::directory_options::skip_permission_denied);
rdi != fs::recursive_directory_iterator();
++rdi) {
auto& de = *rdi;
lastPath = de.path();
if(blacklist.count(de.path())) {
rdi.disable_recursion_pending();
}
else {
// collect info you need here
// ...
}
++rdi;
}
}
catch (fs::filesystem_error& fe) {
if(!blacklist.insert(lastPath).second) {
// exception on same path, double error, something went really wrong
break;
}
else {
// we blacklisted a new entry, reset your collected info here,
// we need to restart
// ...
continue;
}
}
// we are through and managed to get all info
// ...
break;
}
Of course this is a lot of code working around something that should be a single line and only needed on macOS, so if one uses this at all, it should be wrapped away.
One subtle thing to be aware of is that a range-based-for uses the fs::begin(fs::recursive_directory_iterator) function that creates an "invisible" copy, and makes it impossible to call disable_recursion_pending() on the correct instance. This is the reason why a regular for-loop is used.
Another ugly part of that workaround is that besides the standards suggestions neither path1() nor path2() of the exception deliver the offending path and as parsing the exception text is a bad idea, the paths are remembered in the otherwise useless lastPath variable.
All in all it works, but this is nothing I would actually use, as the tree needs to be scanned multiple times (on my notebooks "Application Support" it takes six rescans until it gets through and four times the runtime of an implementation that works without this hack), so I would see this more as an experiment if it is possible to generically iterate the home on macOS with std::filesystem.
So, sadly, until those issues are fixed, std::filesystem::recursive_directory_iterator is not that great on macOS, and I continue to use my drop-in filesystem replacement on that platform, that honors skip_permission_denied for EPERM and EACCES (but is utf-8 only).
I use the kate text editor for writing c++ code. I really like the editor except for its indentation behavior which drives me mad. I have the following problem: If I want to write code like
if( true )
{
//code
}
the indentation messes everything up initially: instead of inserting a tab and jumping to the position marked "//code" when hitting enter, kate just inserts a single blank space. So to describe it more in detail: You start from
if( true )
{//your cursor is here
}
and on pressing enter, kate produces something like
if( true )
{
[ ]//your cursor is here
}
where '[ ]' stands for a single blank space. But instead, I want kate to insert a tabulator to give the result indicated at the start. Or, to repeat it more verbosely, I want that kate gives me
if( true )
{
<tabulator>//your cursor is here
}
on hitting enter. I have played around with all settings and can not make it work. It drives me crazy. I selected "default identation mode normal", "Ident using tabulators" (8 characters). Does anybody know how to customize this behavior? I looked up the katerc file but couldn't find any options that would help me...
edit: I should add that it would be ok if kate would just give me
if( true )
{
//your cursor is here
}
on pressing enter. But this additional blank space is absolutely annoying.
Ok, I tried for half an hour, I don't know why I found out how to do it right AFTER posting the question :). So in case anybody has the same issue, here is the "solution": I missed that kate seems to have a global setting for the indentation mode as well as a local one for every file. In my case - for some reason - my file had special indentation options set. You can alter them via the menu bar by chosing "Tools -> Indentation". This local option overrides the global one! Or the global one is just the default for the local options, I don't know exactly...
You can create a config file .kateconfig and add the variables kate: replace-tabs off; tab-indents: true;
More on this in the manual.
If you have a header file named ThisIsAHeaderFile.h, the following will still locate the file in Visual Studio:
#include <ThisIsAheaderFile.h>
Is there a way to enforce case sensitivity so that the #include will result in an error?
You can't, because the Windows file system is itself case-insensitive.
If you could get into a situation where you had both RICHIE.h and richie.h, it might make sense to control case sensitivity, but you can't.
I would like to point out that this is not an unsolvable problem as many tries to point out to the OP. The case insensitivity is beside the point. The point is as Lorenz03Tx explains in a comment, even though the file system is case insentitive the case is retained, so it can be controlled.
Such a counter measures is really great to have when doing cross platform development, and prevents much after work when the code is compiled for the other platform. Not to forget that making the build process more picky you would induce better habits for the developers, as they gradually will be more consistent how they include and name files.
TL;DR
One solution is to use a script that simply scans the source files for include statements and tries to match them along the include paths. Such a script could be added to visual studio post-build events, and thus run at every build, or (inspired by krlmlr) use the preprocessor of a compiler that enforce case sensitivity.
It is (used to be?) possible to create files with the same name but case differences on NTFS. Maybe someone with cygwin can verify this.
MSDN
Even then, however, it's impossible to access more than one of these at a time from a normal Windows application.
While it might not be possible to enforce this from within Visual Studio, one could implement a quick check by running only the preprocessor on the C/C++ source. This will run quickly enough to be practicable even as post-commit hook in a version control system, and err if the case in file names has been mismatched. So:
Configure your build system in Linux to support preprocessor-only runs (-E with gcc/g++)
Implement a preprocessor-only run as post-commit hook, triggering an early notification to the responsible person and/or to someone willing to routinely fix these errors
Of course, this assumes a VCS as central storage for the code.
Both FAT and NTFS are case insensitive file systems. Foo and fOO are the same file as far as they are concerned. Although the Windows OS will preserve the case you use for a file. If you name a file ThisIsAheaderFile.h it will show up that way in the file system. Although all system function calls to open that file can use any casing they want.
Also having similar problem when trying to build under linux; not full solution...
If you Find in Files #include by VS and copy result to textarea, you will get sorted CSV with include file name, original path and list of files in 3rd column (columns are tab delimited)
Easy to check solution/wide and in case there are not much case problems it should be easy to replace them?
function readIncludes(t)
{
var s = t.value.split('\n');
var res = {};
for(var r in s)
{
if (r == 0) continue;
var dq = s[r].indexOf('(');
var p = s[r].substr(0, dq);
var p2 = s[r].indexOf(':', dq);
p2 = s[r].substring(0, p2);
dq = s[r].indexOf('#', dq);
var i = s[r].substr(dq);
var ip = i.replace(/#include\s+/, "");
if (!ip) continue; // *#includes.*
var st = '<>""';
if (st.indexOf(ip[0]) < 0) continue; // *#include*\S+
st = st[st.indexOf(ip[0]) + 1];
ip = ip.substr(1, ip.indexOf(st, 2) - 1);
if (!ip || ip[0] == '/') debugger
if (!res[ip]) res[ip] = [];
res[ip].push(p2);
}
var resSorted = [];
for(var r in res)
{
var shortR = r.replace(/.+[\\/]/, ""); // include file
resSorted.push(shortR + "\t" + r + "\t" + res[r]); // \tpath\tplaces
}
t.value = resSorted.sort().join('\n'); // sort again long lines of results
}
html,body,textarea {
width: 100%;
height: 100%;
white-space: nowrap;
}
<textarea onchange="readIncludes(this)">
</textarea>
In one of my projects, I need to be able to provide a very simple variable find-and-replace parser (mostly for use in paths). Variables are used primarily during startup and occasionally to access files (not the program's primary function, just loading resources), so the parser need not be high-performance. I would greatly prefer it to be thread-safe, however.
The parser needs to be able to store a set of variables (map<string, string> at the moment) and be able to replace tokens with the corresponding value in strings. Variable values may contain other variables, which will be resolved when the variable is used (not when it is added, as variables may be added over time).
The current variable grammar looks something like:
$basepath$/resources/file.txt
/$drive$/$folder$/path/file
My current parser uses a pair of stringstreams ("output" and "varname"), writes to the "output" stream until it finds the first $, the "varname" stream until the second $, then looks up the variable (using the contents of varname.str()). It's very simple and works nicely, even when recursing over variable values.
String Parse(String input)
{
stringstream output, varname;
bool dest = false;
size_t total = input.length();
size_t pos = 0;
while ( pos < total )
{
char inchar = input[pos];
if ( inchar != '$' )
{
if ( dest ) output << inchar;
else varname << inchar;
} else {
// Is a varname start/end
if ( !dest )
{
varname.clear();
dest = true;
} else {
// Is an end
Variable = mVariables.find(varname.str());
output << Parse(Variable.value());
dest = false;
}
}
++pos;
}
return output.str();
}
(error checking and such removed)
However, that method fails me when I try to apply it to my desired grammar. I would like something similar to what Visual Studio uses for project variables:
$(basepath)/resources/file.txt
/$(drive)/$(folder)/path/file
I would also like to be able to do:
$(base$(path))/subdir/file
Recursing in the variable name has run me into a wall, and I'm not sure the best way to proceed.
I have, at the moment, two possible concepts:
Iterate over the input string until I find a $, look for a ( as the next character, then find the matching ) (counting levels in and out until the proper close paran is reached). Send that bit off to be parsed, then use the returned value as the variable name. This seems like it will be messy and cause a lot of copying, however.
The second concept is to use a char *, or perhaps char * &, and move that forward until I reach a terminating null. The parser function can use the pointer in recursive calls to itself while parsing variable names. I'm not sure how best to implement this technique, besides having each call keep track of the name it's parsed out, and append the returned value of any calls it makes.
The project need only compile in VS2010, so STL streams and strings, the supported bits of C++0x, and Microsoft-specific features are all fair game (a generic solution is preferable in case those reqs change, but it's not necessary at this point). Using other libraries is no good, though, especially not Boost.
Both my ideas seem like they're more complicated and messier than is needed, so I'm looking for a nice clean way of handling this. Code, ideas or documents discussing how best to do it are all very much welcome.
Simple solution is to search for the first ')' in the string, then move backwards to see if there's an identifier preceeded by "$(". If so, replace it and restart your scanning. If you don't find "$(" identifier, then find the next ')' - when there isn't one you're finished.
To explain: by searching for a ) you can be sure that you're finding a complete identifier for your substitution, which then has the chance to contribute to some other identifier used in a subsequent substitution.
EXAMPLE
Had a great time on $($(day)$(month)), did you?
Dictionary: "day" -> "1", "month" -> "April", "1April" -> "April Fools Day"
Had a great time on $($(day)$(month)), did you?
^ find this
Had a great time on $($(day)$(month)), did you?
^^^^^^ back up to match this complete substitution
Had a great time on $(1$(month)), did you?
^ substitution made, restart entire process...
Had a great time on $(1$(month)), did you?
^ find this
etc.
If you have a header file named ThisIsAHeaderFile.h, the following will still locate the file in Visual Studio:
#include <ThisIsAheaderFile.h>
Is there a way to enforce case sensitivity so that the #include will result in an error?
You can't, because the Windows file system is itself case-insensitive.
If you could get into a situation where you had both RICHIE.h and richie.h, it might make sense to control case sensitivity, but you can't.
I would like to point out that this is not an unsolvable problem as many tries to point out to the OP. The case insensitivity is beside the point. The point is as Lorenz03Tx explains in a comment, even though the file system is case insentitive the case is retained, so it can be controlled.
Such a counter measures is really great to have when doing cross platform development, and prevents much after work when the code is compiled for the other platform. Not to forget that making the build process more picky you would induce better habits for the developers, as they gradually will be more consistent how they include and name files.
TL;DR
One solution is to use a script that simply scans the source files for include statements and tries to match them along the include paths. Such a script could be added to visual studio post-build events, and thus run at every build, or (inspired by krlmlr) use the preprocessor of a compiler that enforce case sensitivity.
It is (used to be?) possible to create files with the same name but case differences on NTFS. Maybe someone with cygwin can verify this.
MSDN
Even then, however, it's impossible to access more than one of these at a time from a normal Windows application.
While it might not be possible to enforce this from within Visual Studio, one could implement a quick check by running only the preprocessor on the C/C++ source. This will run quickly enough to be practicable even as post-commit hook in a version control system, and err if the case in file names has been mismatched. So:
Configure your build system in Linux to support preprocessor-only runs (-E with gcc/g++)
Implement a preprocessor-only run as post-commit hook, triggering an early notification to the responsible person and/or to someone willing to routinely fix these errors
Of course, this assumes a VCS as central storage for the code.
Both FAT and NTFS are case insensitive file systems. Foo and fOO are the same file as far as they are concerned. Although the Windows OS will preserve the case you use for a file. If you name a file ThisIsAheaderFile.h it will show up that way in the file system. Although all system function calls to open that file can use any casing they want.
Also having similar problem when trying to build under linux; not full solution...
If you Find in Files #include by VS and copy result to textarea, you will get sorted CSV with include file name, original path and list of files in 3rd column (columns are tab delimited)
Easy to check solution/wide and in case there are not much case problems it should be easy to replace them?
function readIncludes(t)
{
var s = t.value.split('\n');
var res = {};
for(var r in s)
{
if (r == 0) continue;
var dq = s[r].indexOf('(');
var p = s[r].substr(0, dq);
var p2 = s[r].indexOf(':', dq);
p2 = s[r].substring(0, p2);
dq = s[r].indexOf('#', dq);
var i = s[r].substr(dq);
var ip = i.replace(/#include\s+/, "");
if (!ip) continue; // *#includes.*
var st = '<>""';
if (st.indexOf(ip[0]) < 0) continue; // *#include*\S+
st = st[st.indexOf(ip[0]) + 1];
ip = ip.substr(1, ip.indexOf(st, 2) - 1);
if (!ip || ip[0] == '/') debugger
if (!res[ip]) res[ip] = [];
res[ip].push(p2);
}
var resSorted = [];
for(var r in res)
{
var shortR = r.replace(/.+[\\/]/, ""); // include file
resSorted.push(shortR + "\t" + r + "\t" + res[r]); // \tpath\tplaces
}
t.value = resSorted.sort().join('\n'); // sort again long lines of results
}
html,body,textarea {
width: 100%;
height: 100%;
white-space: nowrap;
}
<textarea onchange="readIncludes(this)">
</textarea>