WIP: Implement TDE/tdebase#270 for tdelibs: Extend meaning of "Hidden" files. #163
Closed
VinceR
wants to merge 6 commits from issue/270/tdelibs
into master
Loading…
Reference in new issue
There is no content yet.
Delete Branch 'issue/270/tdelibs'
Deleting a branch is permanent. It CANNOT be undone. Continue?
This pull request addresses the tdelibs portion - there will also be a separate and related pull request for tdebase.
The changes are based on proposed patch submitted in response to a KDE bug filed many years ago.
It should be noted that most of the changes are concerned with changing *DotFiles* to *HiddenFiles* in names. This look like the riskiest part.
The changes have been successfully tested in a test environment -- so far, so good.
TO-DO:
This is a note to myself, no need for comments / review unless you want.
Test Case # 1: demonstrate use of multiple hidden file specifications on normal size directories.
Test Setup
*~,TEMP*,temp*
(note that these are globs, not a regex's)Results
Works correctly, with no apparent issues. Specifics using a more realistic home directory (mine) will be posted once I start doing some "no better test than production" testing:)
This is a note to myself, no need for comments / review unless you want.
Test Case # 2: demonstrate use of a single hidden file specification on large directory.
Test Setup
lib*
/usr/lib64
(7160 hidden items + 320 non-hidden items), in a chroot.Test Scenarios
Speculation
I do not think the delay in Scenario 2b is caused by any of the new code. In other words, I think that any directory with 7160 dotfiles + 320 non-dotfiles would manifest this problem currently.
Here is an excerpt from the code in
tdelibs/tdeio/kdirlister.cpp
, with my unsubstantiated comments:I speculate that it would be more efficient to just initialize another KDirLister structure rather than trying all of these deletes on such a large list.
I have confirmed this. This is limitation (or bug) in current KDirLister::emitChanges() and is not related to the PR.
69fbbb0163
toa30e487eac
2 years agoWhile testing the commit from a couple of days ago, I ran into a problem wherein the Konqueror
kfind
plugin was blowing up onClose
, whether or not any type of search had been activated. I thought the problem was related to the missingdelete(matcher)
(corrected in the latest commit) but that was not it.What I discovered was that when one makes a change to a well-known object such as
KDirLister
, one should probably recompile everything that depends on it. My Gentoo system splits up the tdebase into multiple "applications", so I couldn't simply recompile a package called tdebase.For me, the solution to this particular problem was rebuilding (in Gentoo speak) the
trinity-base/kfind
package which is part of tdebase. Other tdebase packages did not seem affected.There shouldn't be a need to recompile, unless you are changing static libraries. But it is probably recommended to logout and login again, to make sure the new libraries are used. I have seen similar issues when rebuilding "core" elements and a logout/login is a clean start.
It is always essential whether the patch represents a change in the public API/ABI or only internal. It should be kept in mind that the inline function defined in the header may manifest itself as a hidden API/ABI change. If the API/ABI is unchanged, then it should not require rebuild and should be sufficient logout/login, as mentioned by @MicheleC, or run
/opt/trinity/bin/tdeinit
.@VinceR
I will start reviewing and adding comments from tomorrow. It may take a few days to complete, due to my workload and some days off with family.
Again, apologies for the delay, July has been way too busy here.
/**
* Pointer to object that encapsulates criteria for determining whether
* or not a file is "hidden". There is one such object per KDirlister.
KDirlister --> KDirLister 😉
* whether or not an individual filesystem object is "hidden" by
* current matcher criteria.
*/
TDEIO::HiddenFileMatcher *matcher;
All internal members or KDirLister are collected inside the KDirListerPrivate class. Suggest we move the matcher there as well.
"Outsiders" require access to
KDirLister's TDEIO::HiddenFileMatcher
object methods (see TDE/tdebase#273). Specifically intdebase/konqueror/listview/
:konq_listview.cpp/KonqListView::KonqListView(...)
calls thesetCriteria()
method to initialize matcher object with user's stored default match criteria.konq_listview.cpp/KonqListView::slotChangeHiddenFileMatcher()
calls thegetMatchPropertiesFromUser()
method to allow user to change match criteria, either for current running view or as default. It also calls theget_Criteria()
method if updated criteria is to be saved as default.konq_listviewitems.cpp/KonqListViewItem::updateContents()
calls thematch()
method to determine if file is hidden when the "Group Hidden First" sort option is in effect.Not sure we can do that if we hide the object in the private area. But that does beg a question that I posed somewhere inside the code: what are the reasons for storing properties (in this case a pointer) in an object's private structure versus in its declaration in a header file?
In TDE there is a convention to have a "private" class to store the internal details. This is I guess partly historical from KDE3 and partly to provide a cleaner interface, hiding the internal implementation.
After I complete reviewing the PR, I will provide more comments on your other questions above. Maybe we don't need to access the matcher directly from outside or maybe we find another way to do that.
We can add a
matcher()
method toKDirLister
that exposes the underlined matcher object. This would be necessary anyway, because it is recommendable not to leave the object in the public part of the class. So it should be little effort to move the matcher in the privateKDirListerPrivate
class.d = new KDirListerPrivate;
matcher = new TDEIO::HiddenFileMatcher;
Suggest to move to KDirListerPrivate.
}
delete d;
delete matcher;
Suggest to move to KDirListerPrivate.
}
void KDirLister::setShowingDotFiles( bool _showDotFiles )
void KDirLister::setShowingHiddenFiles( bool _showHiddenFiles )
In the function declaration, the name of the parameter was changed to
show
. We should use the same name here for consistency, or change it in the declaration otherwise.return false;
if ( !d->isShowingDotFiles && item->isHidden() )
const_cast<KFileItem*>(item)->setHidden( matcher );
I have not finished reviewing the whole PR, but I struggle to understand why this is needed here.
EDIT:
I think the way
matcher
is used withKFileItem
can be improved. I will write more when I review that section. That would remove the need to call setHidden() here.Moreover it calls a method that could modify
item
, which breaks the promise of thematchesFilter
signature, whereitem
is declared const.See my response to your larger review below - we may be able to get rid of that function.
It was the only way I could get it to work. I note numerous similar examples throughout tdelibs code where similar promises are broken ¯\(ツ)/¯
As I use C++ more, I see things that I consider to be genuine improvements to C. How
const
is handled is not one of them :)As discuss in the
Conversation
section, we should pass thematcher
toisHidden()
and removesetHidden()
continue;
}
(*kit)->setHidden( matcher );
This should no longer be required when we improve the logic for the use of
matcher
The problem I see with the current use of
matcher
inKFileItem
is that each time you want to see if a file is hidden (KFileItem::isHidden()
), we first callKFileItem::SetHidden()
to set the matcher and the property, which is not very clean.I see two possible ways to improve this, depending on what we want to achieve.
pass the matcher to
KFileItem::isHidden()
and determine if a file is hidden or not at that moment. This has the benefit to require less code changes (the wholem_bHiddenFile
logic is not needed anymore), but has the drawback to require evaluation at each call ofKFileItem::isHidden()
, which possibly results in worse performances.The idea behind this solution is that
KFileItem
could be visible or hidden depending on the matcher in use, and we don't need to modify the KFileItem at all, regardless of the matcher in useif we don't want the overhead each time we call
KFileItem::isHidden()
, we can decide that aKFileItem
is visible/hidden at the time it is created or when amatcher
is modified. This requires modifying all KFileItems each time we create them or when we change thematcher
(this also implies remembering all the KFileItem that we need to modify when we change a the matcher). It also means that we can't use different matchers on the sameKFileItem
object.IMO, option 1 is a better design and pretty much what the original code was doing, although with a fixed rule to decide whether a file was visible or not. We would need to see if performances would be drastically affected or not, but I think it should not be much worse than before.
@VinceR, @SlavekB what is your opinion?
An earlier implementation did something like option 1. I now realize that there is probably no need for separate
isHidden()
andSetHidden()
functions. BUT ... the problem I struggled with was the fact thatisHidden()
is being called from other places than within KDirLister code. I do think we still needm_bHiddenFile
to remember a file's "hideability" for such function calls.Would the following code address your concern? We would get rid of
SetHidden()
and callisHidden(matcher)
within the KDirLister codeHi @VinceR, sorry for the late reply, I was on a trip with the family for a few days.
I thought more about this and I am even more convinced that we should implement option 1. The first implementation in this PR does not perform any faster/better since
setHidden
is called whenever we want to callisHidden
, so there would be no performance loss at all.Pretty good, just a couple of improvements.
m_bHiddenFile
at all, we can simply evaluate on the spot whether a file is hidden.matcher
because it would provide a "false" result. I think better to provide a matcher whenever we want to use this functionality. What do you think? If we keep the defaultnullptr
value, we should probably provide the original logic based on the filename as a result for the time when no matcher is provided.Basically a logic similar to the original code, but where the part related to the hidden test is replaced with the call to the matcher.
If we use
m_bHiddenFile
, we would have toIn the next 2 or 3 days I should have enough time to complete the review of this PR. Will likely add some more comments.
To clarify why I think there is a need for property
KFileItem::m_bHiddenFile
:As you can see, my
KFileItem::isHidden(matcher)
code uses this property to cache the most recent result ofmatcher->match(...)
. Why do that? Because there are other callers of this function that do NOT pass aTDEIO::HiddenFileMatcher
object to it. Propertym_bHiddenFile
is for their benefit.Options for handling these callers are as follows:
KDirLister::match
object toKFileItem::isHidden()
. That won't work in code that has no relationship to or visibility into an associatedKDirLister
.KFileItem
object was not created by aKDirLister
object, then return false . This is what I am proposing to do.Here are the calls to
KFileItem::isHidden()
in tdelibs and tdebase that I was able to detect:The code appears to only be concerned with applying transparency to icons for hidden files. There is undoubtedly a
KDirLister
involved somewhere but I didn't see any obvious way to get access to it. But there would be no need to do any code modifications with my preferred option 2 -- the meaning of "hidden" will always be current. Or we could go for option 3 and abandon the icon transparency feature. Not being a big IconView user, I could live with that :)I could not find any users of the
KSimpleFileFilter
class. Maybe that code could be amended to add and implement its ownTDEIO::HiddenFileMatcher *matcher
property as was done in withKDirLister
. We could do that.Test trash program that doesn't get compiled, hmm. Anyway, with no
KDirLister
, the assertion should always succeed.Of course, there might be calls to
KFileItem::isHidden()
in other parts of the TDE codebase.Hi @VinceR
It is a very valid point and it raises two important questions.
The more I think about the functionality we are trying to implement, the more I see a need to have the following things (some of which is already in this PR):
a. a global matcher, used as default when no matcher is specified. By default this should match dot files as the original code. I think using
m_bHiddenFile
makes sense in this context to improve performances across repeated calls.b. a way to edit the global matcher (a dialog like the one in this PR - which I have not review yet btw). Changes would have global effect across TDE whenever the global matcher is used or when no matcher is used
c. a way to specify a custom matcher for a local application. This overrides the default matcher for the specific instance: for example we may want to use a different matcher in a Konqueror window or tab. This point implies having the ability to switch between global (default) matcher and custom matcher
d. a way to edit a custom matcher
I shall also discuss with @SlavekB when he is back from his trip early next week, but I am also interested in what you think about it.
In term of implementation, we can probably aim at implementing a. and b. first (I guess this PR does most of the job already) and later look at adding support for c. and d.
What do you think?
@MicheleC
I think most of those requirements may already be satisfied.
TDEIO::HiddenFileMatcher
object always initializes to matching dotfiles on creation.TDEIO::HiddenFileMatcher
object. It just needs to store / retrieve its application-specific match criteria string as a separate application-specific setting on disk. This PR is doing just that for aKonqListView
paired with an associatedKDirLister
.TDEIO::HiddenFileMatcher
couldn't be allocated and used. The match criteria would be stored in a kdeglobals setting and modified by user through a control panel applet. The global defaults would be available by either using the global instance directly, or by initializing an application-specific matcher from the kdeglobals setting.Yes, a global file matcher with settings in stored in kdeglobals is definetely good. Then we need to have a way to edit that from the TDE control panel.
For the application-specific (but even for the view-specific, think different tabs wanting to use different matchers) we will also need to provide a way to set them from a GUI. But this can come later.
virtual void setFilterDotFiles( bool filter );
virtual void setFilterHiddenFiles( bool filter );
/**
* Checks whether filtering dot files is enabled.
filtering dot files
should change intofiltering hidden files
* This option is enabled by default.
* @param filter true to enable filtering dot files, false to
filtering dot files
should change intofiltering hidden files
}
(*kit)->setHidden( matcher );
if ( (*kit)->isHidden() )
As discuss in the
Conversation
section, we should pass thematcher
toisHidden()
and removesetHidden()
by the HiddenFileMatcher standards pointed to by @param matcher.
Sets @property m_bHiddenFile accordingly.
*/
void setHidden( TDEIO::HiddenFileMatcher *matcher );
As discuss in the
Conversation
section, we should pass thematcher
toisHidden()
and removesetHidden()
.*/
bool isHidden() const;
This method signature should remain as is.
A new
bool isHidden(const TDEIO::HiddenFileMatcher *matcher);
method should be added (note that there isn't aconst
at the end of the signature). This will implement what we discussed in theConversation
section: cache the value ofm_bHiddenFile
and return it. If a nullptr matcher is passed, the global matcher object should be used.Hi @MicheleC,
I have some questions about this. Before your latest suggestions, here is what I had changed in tdeio/tdeio/fileitem.h per earlier discussion:
This handled calling
isHidden()
andisHidden(matcher)
.If I understand you correctly, you are suggesting something like this:
I can do that but I guess I don't understand why it is better. Would we also need two function definitions in fileitem.cpp?
If we do this, we will be forcing the
overlay()
function, which callsisHidden()
, to always use the global definition of hidden instead of the potentially different one that current KDirLister uses.But your suggestion does nicely handle all of those potential calls to
isHidden()
that we do not yet know about. I guess that would be preferable in the long run.Hi @VinceR
It's a subtle thing, but it is a cleaner design.
The first function
bool isHidden() const;
is markedconst
, so it means it won't make any changes to the called object.The second function
bool isHidden( TDEIO::HiddenFileMatcher *matcher);
is not markedconst
, so it is free to change the underlined object (that is to update them_bHiddenFile
flag).Re using
mutable
, it is something I personally stay away from: IMO something is wrong in the design if we need to usemutable
. IMOmutable
is a bad concept in itself and should not even be part of the language. Happy to be proven wrong if anyone has a good use case for it :-)Yes, but basically we already have them. The original
setHidden
becomes the secondisHidden
;-)Not really. By calling
isHidden()
without a matcher, it will return the current cached status of `m_bHiddenFile', so if we change the matcher somewhere else, we would be able to use a custom matcher if needed. That is another benefit of having the two functions above.Doing things the way you suggest results in compile error:
kdirlister.cpp: In member function ‘virtual bool KDirLister::matchesFilter(const KFileItem*) const’: error: passing ‘const KFileItem’ as ‘this’ argument discards qualifiers
To work around this, I changed the function to call
const_cast<KFileItem*>(item)->isHidden( matcher )
instead ofitem->isHidden( matcher )
. But I do remember an earlier objection:It looks like we either need to use
mutable
orconst_cast
to change a property in an otherwise constantKFileItem
.I will be going with
const_cast
in the next commit, we can discuss this further after that.Yeah, let's go for const_cast for the time being, then after you have pushed the next commit, we can review. If it makes sense, we may take away the 'const' from the parameter of the 'matchesFilter' call.
Will wait for the new code and then I will continue the review.
There is one more important fact: If the change would be made the first way – one method with the default value, this will cause immediate breaking of the ABI compatibility and will require rebuild almost everything. While the change made the second way – that is, two methods, it retains compatibility with the existing ABI and smoothly adds new functionality.
I had to think about this for a bit but now I understand the reason why you are right. Thanks for this insight, I will try to avoid ABI incompatibilities in the future :)
&& !isReadable())
_state |= TDEIcon::LockOverlay;
// kdWarning() << "KFileItem::overlays calling isHidden()" << endl;
For consistency with the code around it, we can probably remove this comment
return m_url.fileName()[0] == '.';
else // should never happen
return m_strName[0] == '.';
/* FIXME: Who calls this function? We are aware of the following callers:
Unnecessary comment
}
void KFileItem::setHidden( TDEIO::HiddenFileMatcher *matcher )
Change into
bool KFileItem::isHidden(const TDEIO::HiddenFileMatcher *matcher)
*/
bool m_bHiddenFile:1;
// Auto: check leading dot.
Comments need update too
void KFileItem::setHidden( TDEIO::HiddenFileMatcher *matcher )
{
if ( !m_url.isEmpty() )
Before this code, we should abide to the m_hidden choice provided by:
* True if file is "hidden" (i.e. hide-able)
by current HiddenFileMatcher standards
*/
bool m_bHiddenFile:1;
How about renaming this to
m_bHiddenByMatcher
? It's more specific. There is already a m_hidden property which can beAuto, Hidden, Shown
. In case ofAuto
, he matcher will define whether the file is shown or not, hence the new suggested name.m_bLink( false ),
m_bIsLocalURL( _url.isLocalFile() ),
m_bMimeTypeKnown( false ),
m_bHiddenFile( false ),
In the construct body we should call
isHidden(nullptr)' to make sure
m_bHiddenFilestores the correct value based on the global matcher. Otherwise if we cann
isHidden()(without matcher) somewhere else before ever calling
isHidden(matcher)`, we risk getting the wrong result (false instead of the actual hiding status).Just noticed there is a call to
init()
in all constructors. We can do this inside theinit()
function, so it covers all constructors in one shot.m_bLink( false ),
m_bIsLocalURL( _url.isLocalFile() ),
m_bMimeTypeKnown( false ),
m_bHiddenFile( false ),
Same as above
m_bLink( false ),
m_bIsLocalURL( url.isLocalFile() ),
m_bMimeTypeKnown( !mimeType.isEmpty() ),
m_bHiddenFile( false ),
Same as above
@VinceR After adjusting the points we discussed so far, would you mind (force-)pushing the updated code before I continue the review? We have already many changes and it is better to realign on the code
MicheleC, I am almost done with changes and limited testing. Implementation of a single global hidden file matcher in addition to application-specific instances turned out to be trickier than I predicted so I need a bit more time with "real" system testing.
Give me a couple of days, then I will push updated code and we can proceed from there.
Sure, no worries @VinceR. Take the time that is needed.
I would even suggest we break down this in multiple parts, if it is easier. something like this:
We can then test and merge one part at a time.
@MicheleC,
This took somewhat longer than I expected but I finally have some updates for us to discuss. I think I hit just about every point you brought up. The new code is actively used/tested on my main system. I believe everything is working correctly, especially in conjunction with tdebase commit
8481f9c3f4
.That said, I am not quite satisfied with how things are implemented in
KDirLister
andKFileItem
. After you have completed your next round of reviews of the current code, I want to discuss with you an idea whereinKFileItem
maintains and uses its ownHiddenFileMatcher*
variable, initialized to theGlobalHiddenFileMatcher->getInstance()
, and updated (once) byKDirlister
to point to its ownHiddenFileMatcher*
. Doing this might eliminate the need for 2 variants ofisHidden()
.Thanks for the update @VinceR. I have to apologize in advance because most likely I will only be able to have a detail look at this next weekend, another busy work week ahead and some pending things to finish first :-(
@VinceR I am finally back to this PR. Will start reviewing from tomorrow. Sorry for the delay :-)
Hi @VinceR,
after reviewing the current code, I think your idea is good. KFileItems are created and used in many places, which makes dealing with them quite tricky. Your idea should help keep this simple, as long as we implement it carefully.
Moving forward, we should have something like this in place:
isHidden()
will use the current matcher to determine if an item is hidden or not. There is no more any need to have two differentisHidden
methods.Following the model used for TDELocale, I suggest we proceed as follow for the global matcher:
Once all the above is in place, we can move to KDirLister and other places that use KFileItems and the matchers, including the GUI to set/modify the matcher in use. You may want to consider implementing the steps above as a new PR, to keep the code cleaner.
This PR is quite big, so let's address it and merge it step by step. Trying to do all in one go is a massive job and it helps to break it down in smaller chunks and verify that all is still working along the way.
@MicheleC,
I am glad you were recently delayed in getting back to reviewing this PR because I also have been too busy to do any more work on it!. Your comments reflect what I have been thinking would be the next step. Here are some of my selective responses to them:
Actually we would use it right away to enable functionality for Konqueror listview (via associated KDirLister). But if you want to break up the PR, I guess we could save that part for later.
I don't quite follow this, but I still need to look at the TDELocale methodology. As long as there is a single pre-initialized instance of a "global" HiddenFileMatcher that other code can reference, it will all work just fine.
That is probably a wise course of action. I guess I need to make another branch (just for myself for the while) that splits off the additional stuff I am doing in KDirLister.
This will take a bit longer while I do the necessary research, coding, and testing.
Many thanks for working with me on this,
Vince
Basically TDEGlobal will instantiate and provide access to a global HiddenFileMatcher. By default, this should provide the current behavior, that is filter out files that start with a dot. I haven't really commented about the HiddenFileMatcher class yet, although at a first glance I will some feedback to provide. Let me know if you prefer to have that now or after you create the new PR.
Yes, probably wiser to use a different branch. We can keep this PR for reference, so the rest of the code is available while in the meantime we work through another branch step by step
No worries, happy to work together and share knowledge. Any little bit helps to make TDE a better DE!!
@MicheleC,
I will be starting a new PR to simplify the code review and implementation process. The changes in that PR will be introduced incrementally as follows:
TDEStringMatcher
and aTDEHiddenFileMatcher
that inherits from it. Implement the first "user" ofTDEHiddenFileMatcher
as a single instanceTDEGlobal::hiddenFileMatcher()
KFileItem
to use its ownTDEHiddenFileMatcher*
inisHidden()
, initialized to the global instance and replaceable via an externally callable method. I am hoping to also retain and improve current match caching.KDirLister
to use its ownTDEHiddenFileMatcher*
which it can pass on to eachKFileItem
as it gets created.Since what I have in the current PR already works just fine, I feel compelled to retrofit any changes in the new PR back to this one for complete testing before I submit them for your review. That will cause some delay but I would feel better that you are reviewing code that actually works :)
I am ALMOST done with (1) and just need to do some testing. I am hoping to have the new PR ready for you by Wednesday.
@VinceR,
sounds like a good plan forward 👍 If I may suggest, it may be better to do 1. and 2. first, then test, merge and make sure all apps work as expected after a rebuild (they should) and then we move to 3.
Not sure why we need a
TDEStringMatcher
-TDEHiddenFileMatcher
hierarchy, but will wait to see the code before further comments. If such structure is useful, we shall go for it.Take your time. It's another busy week at work, so most likely I won't review before the weekend anyway :-)
Since I am leaving on a weeklong vacation tomorrow, I won't have enough time to fully implement and test (2). In order to give you something to look at, I wanted to submit (1) since that is ready (and tested, albeit with all the other baggage in this PR).
If you want to postpone review until I get to (2), that's OK -- ETA will be 13 September. I suppose I also ought to add a proper control module as well.
Since TDEHiddenFileMatcher class provides a special purpose iterative string matching function, I thought it might be nice to also provide a more general class that applications can use for other purposes
So instead of reviewing another PR, you can just relax :)
Hi @VinceR,
hope you are enjoying your holiday :-)
I am ok to review either (1) only or (1) and (2) together. In fact I thought you had pushed a PR with (1) only and wanted to review it today, but I can't seem to find it. I guess I may have misunderstood your prev comment.
Once you are back and ready, let me know and we resume the discussion.
Hi @MicheleC,
I am back and just created a new PR #178. I am hoping it will be easier to navigate than this one which ended up with a lot of RnD. Hopefully the commit messages and my introductory comments in the new PR will help you proceed with your review more easily.
VinceR
Hi Vince, will have a look thorugh the weekend, or earlier if find the time.
@VinceR
I started the review and there are lot of comments. I have published what done so far to make sure Firefox does not play tricks and lose all the comments made till now. I will continue the review tomorrow and if needed Monday, so please hold on till I complete it and I further ping you on this PR.
I hope the big amount of comments is not discouraging you, on the contrary that it serves as guidance for refining the solution.
@VinceR
to avoid keeping too many PR open and create confusion, is it ok if we mark this one as closed?
Also since the code has changed quite a bit with review on PR #178, would it be ok to delete the branch associated with this PR? This is mostly to keep the tdelibs repo as clean as possible. If you think the code in this PR is still required, we can leave the branch around for longer, no problem.
Yes, go ahead and close the PR and remove the branch. I assume I will still be able to get back to the comments in this PR.
While branch
issue/270/tdelibs
is still the one I do active development & testing, I will not be doing any more pushes from it. Instead, I will selectively port changes to branchissue/270/tdelibs-V2
for your review.Please keep related tdebase PR#273 open for the time being.
Actually, this won't be an issue. I archived the web page & associated resources locally.
The comments and code remain available through gitea, so you can always come back here if you need to review things. In fact, the commits remain available in git too, if you checkout by hash. The only things that disappear is the branch pointer in git, which helps in keeping the repo cleaner.