Jak automatycznie usunąć końcowe spacje w programie Visual Studio 2008?

122

Czy można skonfigurować program Visual Studio 2008 tak, aby automatycznie usuwał białe znaki na końcu każdego wiersza podczas zapisywania pliku? Wygląda na to, że nie ma wbudowanej opcji, więc czy są dostępne jakieś rozszerzenia, które to zrobią?

ChrisN
źródło
1
Uwaga dla czytających to, którzy używają Visual Studio 2010: Jeśli zainstalujesz rozszerzenie PowerCommands firmy Microsoft, możesz automatycznie sformatować dokument podczas zapisywania pliku (włącz tę funkcję za pomocą Narzędzia / Opcje). Spowoduje to między innymi usunięcie niepotrzebnych końcowych białych znaków.
steinar

Odpowiedzi:

68

CodeMaid to bardzo popularne rozszerzenie programu Visual Studio, które robi to automatycznie wraz z innymi przydatnymi porządkami.

Ustawiłem go tak, aby czyścił plik przy zapisywaniu, co moim zdaniem jest domyślne.

arserbin3
źródło
1
To najlepsze rozwiązanie na tej stronie. Jest łatwo konfigurowalny, automatycznie wykonywany na żądanie lub przy zapisie, ładnie integruje się z VS, ma wiele innych bardzo przydatnych funkcji. Dobrze znaleźć arserbin3.
Chris R,
Nie ma możliwości wyłączenia pełnego formatowania kodu w tym rozszerzeniu, więc jest ono niekompatybilne na przykład z niestandardowymi stylami wcięć.
aemxdp
@Andriy Nie rozumiem, co masz na myśli. Podąża za dowolnym niestandardowym wcięciem ustawionym w Visual Studio. Ustaw je w Narzędzia> Opcje> Edytor tekstu> [Język]> Karty
arserbin3
@ arserbin3 Mam na myśli to, że jeśli chcesz sformatować swój kod w ten sposób - pastebin.com/uJqBQ1u2 - nie masz szczęścia, ponieważ po zapisaniu automatycznie sformatuje kod taki jak pastebin.com/761Lzra7 lub coś takiego, w zależności od opcje. Nie ma też możliwości całkowitego wyłączenia reguł wcięć. A bez codemaid ponowne formatowanie pliku nie przebiega automatycznie, więc możesz zapisać plik z tego rodzaju wcięciem.
aemxdp
6
@ arserbin3 Myślę, że nie masz racji Andriya. Pracuję w dużym projekcie open source. Nie jestem właścicielem kodu - współtworzę kod. Nie mogę zmienić wytycznych dotyczących wcięć w projekcie. Chcę, aby VisualStudio usuwał końcowe spacje, gdy modyfikuję jakiś plik, i nie mam nic wspólnego z czymkolwiek innym w pliku (tabulatory, spacje, wcięcia itp.). Jak dotąd VisualStudio jest jedynym IDE, z którym pracuję i które nie może tego zrobić. Każdy inny niedopracowany edytor (nie mówiąc już o IDE) może to zrobić. Nie mogę skonfigurować CodeMaid do pewnego formatowania, ponieważ formatowanie jest różne.
kliteyn
71

Znajdź / zamień za pomocą wyrażeń regularnych

W oknie dialogowym Znajdź i zamień rozwiń opcje Znajdź , zaznacz Użyj , wybierz Wyrażenia regularne

Znajdź co : „ :Zs#$

Zamień na : „”

kliknij Zamień wszystko

W innych edytorach ( zwykły parser wyrażeń regularnych) „ :Zs#$” byłoby „ \s*$”.

Greg Ogle
źródło
44
W VS2012 użyłbym:[^\S\r\n]+(?=\r?$)
M. Dudley
4
Jeśli używasz zakładek, [:Zs\t]#$jest to przydatna adaptacja.
dlanod
Jak powiązać to ze zdarzeniem Plik przy zapisywaniu, aby było wykonywane za każdym razem, gdy zapisuję plik?
David Ferenczy Rogožan
30

Aby zrobić to za Ciebie, możesz utworzyć makro, które będzie wykonywane po zapisaniu.

Dodaj następujące elementy do modułu EnvironmentEvents dla swoich makr.

Private saved As Boolean = False
Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) _
                                         Handles DocumentEvents.DocumentSaved
    If Not saved Then
        Try
            DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                                 "\t", _
                                 vsFindOptions.vsFindOptionsRegularExpression, _
                                 "  ", _
                                 vsFindTarget.vsFindTargetCurrentDocument, , , _
                                 vsFindResultsLocation.vsFindResultsNone)

            ' Remove all the trailing whitespaces.
            DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                                 ":Zs+$", _
                                 vsFindOptions.vsFindOptionsRegularExpression, _
                                 String.Empty, _
                                 vsFindTarget.vsFindTargetCurrentDocument, , , _
                                 vsFindResultsLocation.vsFindResultsNone)

            saved = True
            document.Save()
        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Trim White Space exception")
        End Try
    Else
        saved = False
    End If
End Sub

Używam tego od jakiegoś czasu bez żadnych problemów. Nie stworzyłem makra, ale zmodyfikowałem je z tego w ace_guidelines.vsmacros, które można znaleźć za pomocą szybkiego wyszukiwania w Google.


źródło
8
Zauważ, że to również zastępuje tabulatory dwoma spacjami.
crdx
Gdzie umieszczasz te skrypty zdarzeń dokumentów?
xagyg
Czy nie byłoby lepiej zrobić to przed zapisaniem, żeby nie otrzymać irytującej zachęty VS, która mówi: „Hej, tekst zmienił się od ostatniego zapisu. Czy chcesz załadować ponownie?”
jedmao
2
Niestety nie ma już makr w VS 2013.
Nathan Baulch
17

Przed zapisaniem możesz użyć skrótu automatycznego formatowania CTRL+ K+ D.

Vyrotek
źródło
11

Możesz to łatwo zrobić, wykonując te trzy czynności:

  • Ctrl+ A(zaznacz cały tekst)

  • Edycja -> Zaawansowane -> Usuń poziome odstępy

  • Edycja -> Zaawansowane -> Wybór formatu

Poczekaj kilka sekund i gotowe.

Jest w stanie Ctrl+ Z'na wypadek, gdyby coś poszło nie tak.

iPixel
źródło
1
Jest do tego skrót: ctrl + w, a następnie wpisz Edit.RemoveHorizontalWhitespace
Josh
8

Biorąc elementy ze wszystkich udzielonych już odpowiedzi, oto kod, który otrzymałem. (Piszę głównie kod w C ++, ale w razie potrzeby łatwo jest sprawdzić różne rozszerzenia plików).

Dziękujemy wszystkim, którzy wnieśli swój wkład!

Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) _
    Handles DocumentEvents.DocumentSaved
    Dim fileName As String
    Dim result As vsFindResult

    Try
        fileName = document.Name.ToLower()

        If fileName.EndsWith(".cs") _
        Or fileName.EndsWith(".cpp") _
        Or fileName.EndsWith(".c") _
        Or fileName.EndsWith(".h") Then
            ' Remove trailing whitespace
            result = DTE.Find.FindReplace( _
                vsFindAction.vsFindActionReplaceAll, _
                "{:b}+$", _
                vsFindOptions.vsFindOptionsRegularExpression, _
                String.Empty, _
                vsFindTarget.vsFindTargetFiles, _
                document.FullName, _
                "", _
                vsFindResultsLocation.vsFindResultsNone)

            If result = vsFindResult.vsFindResultReplaced Then
                ' Triggers DocumentEvents_DocumentSaved event again
                document.Save()
            End If
        End If
    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Trim White Space exception")
    End Try
End Sub
ChrisN
źródło
2

Niestety używam programu VWD 2010 Express, w którym makra nie są obsługiwane. Więc po prostu zrobić kopiuj / wklej do Notepad ++ górnym lewym menu Edit> Blank Operations> Trim Trailing Spaceistnieją inne związane z nimi operacje dostępne. Następnie skopiuj / wklej z powrotem do programu Visual Studio.

Można również użyć NetBeans zamiast Notepad ++, który ma „Usuń końcowe spacje” w menu „Źródło”.

Evgenii
źródło
Po prostu znajdź / zamień: b + $ z pustym ciągiem i możesz to zrobić w ekspresowych wydaniach VS.
zalegalizować
1

Jeśli nie jest to projekt jednoosobowy, nie rób tego. Porównywanie lokalnych plików z repozytorium kodu źródłowego musi być trywialne, a wyczyszczenie białych znaków zmieniłoby wiersze, których nie trzeba zmieniać. Absolutnie rozumiem; Uwielbiam, gdy moje białe znaki są jednolite - ale jest to coś, z czego powinieneś zrezygnować, aby uzyskać czystszą współpracę.

Kevin Conner
źródło
17
Większość dobrych narzędzi porównujących ignoruje nieistotne różnice, takie jak końcowe białe znaki. Jeśli Twoje narzędzie nie działa, pobierz Beyond Compare ze strony scootersoftware.com
Jim McKeeth
19
Jeśli wszyscy w firmie / projekcie to zrobią, różnice będą czyste. Wystarczy raz wyczyścić wszystkie spacje. Wtedy masz pojedyncze zatwierdzenie, które naprawia tylko białe spacje i nie ma żadnych problemów ze znakami w przyszłości.
ThiefMaster
To prawda. Ale to, czy to poleci, będzie zależeć od zespołu. Dodanie jednego dodatkowego kroku do pracy wszystkich lub nawet jednego dodatkowego ustawienia w celu zachowania synchronizacji zwykle tworzy niepotrzebne tarcia. Jeśli zespół może się zmienić lub jeśli członkowie zespołu mogą wybrać własne IDE itp., Proponuję po prostu pozostawić białe spacje. To nie jest taka wielka sprawa.
Kevin Conner
3
Problem z czyszczeniem białych znaków i wcięć polega na tym, że zmniejsza skuteczność funkcji kontroli źródła, takich jak adnotacje, i jest to problem, którego Beyond Compare nie rozwiąże. Lepiej zrobić to dobrze za pierwszym razem.
jammycakes
4
@KevinConner IMO wydaje się o wiele trudniejsze, aby zachować spójność niewłaściwych białych znaków, niż naprawić to raz za pomocą gigantycznego zatwierdzenia białych znaków na początku projektu. Wtedy każdy, którego edytor jest głupi i zepsuty, będzie wiedział o tym, kiedy sprawdzi swoje różnice przed zatwierdzeniem.
Dan Bechard
1

Myślę, że wersja Jeffa Muira mogłaby być trochę ulepszona, gdyby tylko przycinała pliki z kodem źródłowym (w moim przypadku C #, ale łatwo jest dodać więcej rozszerzeń). Dodałem również sprawdzenie, czy okno dokumentu jest widoczne, ponieważ niektóre sytuacje bez tego sprawdzenia pokazują dziwne błędy (na przykład pliki LINQ to SQL '* .dbml').

Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) Handles DocumentEvents.DocumentSaved
    Dim result As vsFindResult
    Try
        If (document.ActiveWindow Is Nothing) Then
            Return
        End If
        If (document.Name.ToLower().EndsWith(".cs")) Then
            document.Activate()
            result = DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, ":Zs+$", vsFindOptions.vsFindOptionsRegularExpression, String.Empty, vsFindTarget.vsFindTargetCurrentDocument, , , vsFindResultsLocation.vsFindResultsNone)
            If result = vsFindResult.vsFindResultReplaced Then
                document.Save()
            End If
        End If
    Catch ex As Exception
        MsgBox(ex.Message & Chr(13) & "Document: " & document.FullName, MsgBoxStyle.OkOnly, "Trim White Space exception")
    End Try
End Sub
David Abella
źródło
0

Myślę, że mam wersję tego makra, która nie zawiesza VS2010 podczas refaktoryzacji, a także nie zawiesza IDE podczas zapisywania plików nietekstowych. Spróbuj tego:

Private Sub DocumentEvents_DocumentSaved( _
    ByVal document As EnvDTE.Document) _
    Handles DocumentEvents.DocumentSaved
    ' See if we're saving a text file
    Dim textDocument As EnvDTE.TextDocument = _
        TryCast(document.Object(), EnvDTE.TextDocument)

    If textDocument IsNot Nothing Then
        ' Perform search/replace on the text document directly
        ' Convert tabs to spaces
        Dim convertedTabs = textDocument.ReplacePattern("\t", "    ", _
            vsFindOptions.vsFindOptionsRegularExpression)

        ' Remove trailing whitespace from each line
        Dim removedTrailingWS = textDocument.ReplacePattern(":Zs+$", "", _
            vsFindOptions.vsFindOptionsRegularExpression)

        ' Re-save the document if either replace was successful
        ' (NOTE: Should recurse only once; the searches will fail next time)
        If convertedTabs Or removedTrailingWS Then
            document.Save()
        End If
    End If
End Sub
juliański
źródło
0

Używam ArtisticStyle (C ++), aby to zrobić, a także ponownie formatuję mój kod. Musiałem jednak dodać to jako narzędzie zewnętrzne i musisz je uruchomić samodzielnie, więc może ci się to nie spodobać.

Jednak uważam za doskonałe, że mogę sformatować kod w bardziej niestandardowy sposób (na przykład parametry funkcji wielowierszowej), ponieważ mogę zapłacić cenę ręcznego uruchomienia. Narzędzie jest bezpłatne.

Marcin Gil
źródło
0

Opierając się na odpowiedzi Dyaus i wyrażeniu regularnym z raportu połączenia , oto makro, które obsługuje zapisz wszystko, nie zastępuje tabulatorów spacjami i nie wymaga zmiennej statycznej. Jego możliwy minus? Wydaje się trochę powolne, być może z powodu wielu wywołań FindReplace.

Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) _
                                         Handles DocumentEvents.DocumentSaved
    Try
        ' Remove all the trailing whitespaces.
        If vsFindResult.vsFindResultReplaced = DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                             "{:b}+$", _
                             vsFindOptions.vsFindOptionsRegularExpression, _
                             String.Empty, _
                             vsFindTarget.vsFindTargetFiles, _
                             document.FullName, , _
                             vsFindResultsLocation.vsFindResultsNone) Then
            document.Save()
        End If
    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Trim White Space exception")
    End Try
End Sub

Dla każdego, kto próbuje użyć tego w dodatku Visual Studio 2012, wyrażenie regularne, którego użyłem, to [ \t]+(?=\r?$)(nie zapomnij w razie potrzeby uciec przed ukośnikami odwrotnymi). Przyjechałem tu po kilku próbach daremnych naprawić problemy z surowego konwersji z {:b}+$braku odpowiednio do powrotu karetki.

Michael Urman
źródło
-1

To jest naprawdę dobry przykład, jak usunąć końcowe białe spacje. Jest kilka rzeczy, które chciałbym zmienić w oparciu o to, co odkryłem za pomocą tego makra. Przede wszystkim makro automatycznie konwertuje tabulatory na spacje. Nie zawsze jest to pożądane i może prowadzić do pogorszenia sytuacji dla osób kochających karty (zazwyczaj oparte na Linuksie). Problem z tabulatorami nie jest tak naprawdę tym samym, co problem z dodatkowymi białymi znakami. Po drugie, makro zakłada, że ​​zapisywany jest tylko jeden plik naraz. Jeśli zapiszesz wiele plików na raz, nie usunie to prawidłowo białych znaków. Powód jest prosty. Bieżący dokument jest uważany za dokument, który możesz zobaczyć. Po trzecie, nie sprawdza błędów w wynikach wyszukiwania. Te wyniki mogą dać lepsze informacje o tym, co robić dalej. Na przykład, jeśli nie zostanie znaleziona i zastąpiona żadna spacja, nie ma potrzeby ponownego zapisywania pliku. Ogólnie rzecz biorąc, nie podobało mi się, że flaga globalna jest zapisywana lub nie. Zwykle prosi o kłopoty w oparciu o nieznane stany. Podejrzewam, że flaga została dodana wyłącznie po to, aby zapobiec nieskończonej pętli.

    Private Sub DocumentEvents_DocumentSaved(ByVal document As EnvDTE.Document) _
                                         Handles DocumentEvents.DocumentSaved
    Dim result As vsFindResult
    'Dim nameresult As String

    Try
        document.Activate()

        ' Remove all the trailing whitespaces.
        result = DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                             ":Zs+$", _
                             vsFindOptions.vsFindOptionsRegularExpression, _
                             String.Empty, _
                             vsFindTarget.vsFindTargetCurrentDocument, , , _
                             vsFindResultsLocation.vsFindResultsNone)

        'nameresult = document.Name & " " & Str$(result)

        'MsgBox(nameresult, , "Filename and result")

        If result = vsFindResult.vsFindResultReplaced Then
            'MsgBox("Document Saved", MsgBoxStyle.OkOnly, "Saved Macro")
            document.Save()
        Else
            'MsgBox("Document Not Saved", MsgBoxStyle.OkOnly, "Saved Macro")
        End If

    Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Trim White Space exception")
    End Try

End Sub

Dodałem okna komunikatów debugowania, aby pomóc zobaczyć, co się dzieje. To bardzo wyraźnie pokazało, że zapis wielu plików nie działa. Jeśli chcesz się nimi bawić, odkomentuj te linie.

Kluczową różnicą jest użycie document.Activate () do wymuszenia przeniesienia dokumentu do aktywnego bieżącego dokumentu na pierwszy plan. Jeśli wynikiem jest 4, oznacza to, że tekst został zastąpiony. Zero oznacza, że ​​nic się nie stało. Zobaczysz dwa zapisy dla każdego pliku. Pierwsza zastąpi, a druga nic nie zrobi. Potencjalnie mogą wystąpić problemy, jeśli funkcja save nie może zapisać pliku, ale miejmy nadzieję, że to zdarzenie nie zostanie wywołane, jeśli tak się stanie.

Przed powstaniem oryginalnego skryptu nie wiedziałem, jak działa skrypt w Visual Studio. Jest nieco zaskakujące, że używa Visual Basic jako głównego interfejsu, ale działa dobrze do tego, co musi zrobić.

Jeff Muir
źródło
Jedną ze zmian jest obsługa zapisywania i przywracania fokusu do okna, które miało fokus w momencie rozpoczęcia zapisywania. Wystarczy zapisać aktywny dokument po Try (używając currdoc = DTE.ActiveDocument), a przed dokumentem.Activate (). Po zakończeniu zapisywania po prostu uaktywnij oryginalny dokument (currdoc.Activate ()). Wygląda to trochę zabawnie, gdy zmienia się fokus podczas zapisywania, ale jest to lepsze niż utrata koncentracji na kodzie, którego nie oglądałeś.
Jeff Muir
-1

Prostym dodatkiem jest usunięcie powrotu karetki podczas zapisywania.

' Remove all the carriage returns.
result = DTE.Find.FindReplace(vsFindAction.vsFindActionReplaceAll, _
                             "\x000d\x000a", _
                             vsFindOptions.vsFindOptionsRegularExpression, _
                             "\x000a", _
                             vsFindTarget.vsFindTargetCurrentDocument, , , _
                             vsFindResultsLocation.vsFindResultsNone)

Kluczem do tego działania jest zmiana \ x000d \ x000a na \ x000a. Przedrostek \ x wskazuje wzorzec Unicode. Zautomatyzuje to proces przygotowywania plików źródłowych dla systemów Linux.

Jeff Muir
źródło