Il mio primo Addin per Visual Studio 2005

Premessa
Nei giorni scorsi, si è sviluppata, tra noi bloggers di Visual-Basic Tips & Tricks, una discussione su due tipi di problemi: un buon blog-editor che funzioni con .Text (ormai antiquato, ma per il nuovo portale si deve ancora attendere) - problema risolto con Windows Live Writer - e uno strumento per formattare il codice che riportiamo nei blog secondo la colorazione di sintassi di Visual Studio.

Per risolvere questo secondo problema, che mi affligge anche quando devo preparare gli articoli per l'area articoli tecnici del nostro sito, ho percorso diverse strade.

  1. Ho scaricato il CodeColorizer di CarloAg (questo prima di conoscere WLW) che aveva però il problema di scrivere una pagina, con tanto di intestazione e pubblicità. Ero costretto a trovare e delimitare la parte da copiare. Non solo: dovevo anche 'passare' questo risultato in TextPad, per sottoporlo ad una macro appositamente creata che mi sostituisse parecchie cose (non sto ad elencarle). Insomma, mi stavo solo arrangiando.
  2. Conosciuto WLW, speravo che avesse qualcosa di predisposto, ma non ha nemmeno lo stile di paragrafo PREformattato. Però sono stati sviluppati per esso dei Plugin, tra cui PasteSourceAsHtml, che si propone come complementare dell'Addin CopySourceAsHtml. Ma anche questa soluzione presentava parecchi inconvenienti nel risultato e nella meccanica d'uso. Andava benissimo per passare da VS a WLW, ma non era sufficiente per usarlo con DreamWeaver, quando scrivevo articoli (dovevo comunque passare attraverso WLW, appunto, come prima passavo da TextPad).
  3. Così mi sono messo a modificare il Plugin PasteSourceAsHtml, pensando che il problema stesse lì. Invece ho scoperto che si limitava a fare quello che faremmo noi con CTRL-V o Shift-Ins o CTRL-P. Decisamente una presa in giro. Però, scoperto questo, ho potuto a mio agio mettermi a 'lavorare' il risultato fornito da CopySourceAsHtml, togliendo le cose che mi davano fastidio e sistemando i tag da me preferiti nel modo più consono.
  4. Come soluzione, era ancora da ritenersi provvisoria, visto che ero costretto ad aprire WLW solo per usare il plugin: dovevo trovare il modo di intervenire direttamente alla fonte, al momento della copia da VS.
    Così, ieri ho scaricato anche il sorgente di CopySourceAsHtml e mi sono messo ad analizzarlo. (Nel frattempo, Rudy - vedi il suo blog - aveva sviluppato un altro plugin per WLW, che non risolveva comunque il mio problema: dovevo proprio provare da me).

Troppa roba
Il codice di CopySourceAsHtml è una scoeprta dell'acqua calda, nel senso che è bello e complesso e ben fatto e tutto quanto, ma usa una strategia per me sbagliata: si mette a rifare quanto già fa VS, leggendo il codice scritto, riconoscendo i token qualificanti del linguaggio e colorandoli come si deve, usando i tag html.

A parte le scelte (secondo me sbagliate, dei tag da usare), considero del tutto inutile questo lavoro di decodifica. Doveva esserci il modo di sfruttare il lavoro già fatto da VS.

In questo frangente, mi è venuto in mente che Stefano Castelli aveva appena scritto un ottimo articolo a proposito della ClipBoard. Ho fatto quindi una prova ed ho scoperto che tra i formati presenti negli Appunti, quando vi si copia del codice da VS, c'è il buon vecchio Rich Text Format.

Eureka!
Ecco fatto. Scoperta la strada giusta, ho analizzato i risultati del dato in formato RTF ed ho pianificato la loro conversione in Html. Quindi ho iniziato un progetto di Addin.

Il Wizard mi ha prodotto parecchio codice, ma solo lo scheletro. Non sapevo letteralmente dove mettermi a sviluppare, e non avevo voglia di studiare chissà quante pagine di MSDN per risolvere quello che in fondo è un problemino di poco conto.

Allora ho riaperto CopySourceAsHtml e l'ho studiato meglio. Fra MSDN e l'analisi del sorgente, sono riuscito a capire i fondamenti di un Addin e ad individuare i punti giusti dove implementare il codice nel mio Addin.

Semplice
Dal codice di CopySourceAsHtml, ho copiato l'idea di aggiungere il menu del mio Addin anche al menu contestuale.
Ho scritto pochissimo codice.
Ho preparato il vettore dei colori:

  Dim colors() As String = {"#000000", "#0000FF", "#00FFFF", "#00FF00", _
"#FF00FF", "#FF0000", "#FFFF00", "#FFFFFF", _
"#000080", "#008080", "#008000", "#800080", _
"#800000", "#808000", "#808080", "#C0C0C0"

 Ho inserito le inizializzazioni dei menu nella OnConnection:

  Public Sub OnConnection(...
...
'Find the Tools command bar on the MenuBar command bar: Dim editControl As CommandBarControl = menuBarCommandBar.Controls.Item(editMenuName) Dim editPopup As CommandBarPopup = CType(editControl, CommandBarPopup) ' trova il commandbar del menu contestuale della finestra di codice Dim editContextMenu As CommandBar = commandBars.Item("Code Window") Try 'Add a command to the Commands collection: Dim command As Command = commands.AddNamedCommand2(addInInstance, "cdCopySourceAsHtml", "cdCopySourceAsHtml", "Executes the command for cdCopySourceAsHtml", True, 59, Nothing, CType(vsCommandStatus.vsCommandStatusSupported, Integer) + CType(vsCommandStatus.vsCommandStatusEnabled, Integer), vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton) ' aggiunge il comando ai due menu (Edit del menu principale e contestuale) Dim i As Integer = CopyCommandPosition(editPopup.CommandBar) command.AddControl(editPopup.CommandBar, i + 1) i = CopyCommandPosition(editContextMenu) command.AddControl(editContextMenu, i + 1) ...
End Sub

 Ho implementato il metodo per trovare la posizione giusta (in modo completamente differente da quello usato in CopySourceAsHtml):

  Private Function CopyCommandPosition(ByVal menu As CommandBar) As Integer
    Dim ret As Integer = 1
    For i As Integer = 1 To menu.Controls.Count
      If menu.Controls.Item(i).Caption.Replace("&", "") = "Copy" Then
        ret = i
        Exit For
      End If
    Next
    Return ret
  End Function

 Ho modificato il metodo Exec quel tanto che basta:

    If executeOption = vsCommandExecOption.vsCommandExecOptionDoDefault Then
      If commandName = "cdCopySourceAsHtml.Connect.cdCopySourceAsHtml" Then
        CopyAsHtml()
        handled = True
        Exit Sub
      End If
    End If

 Ho infine implementato il metodo che fa il lavoro per cui è nato l'addin:

  Private Sub CopyAsHtml()
    ' agisce solo se è selezionato del testo
    If Not String.IsNullOrEmpty(Me.applicationObject.ActiveDocument.Selection.ToString) Then
      ' copia il codice selezionato nella ClipBoard
      DirectCast(Me.applicationObject.ActiveDocument.Selection, TextSelection).Copy()
      ' estrae il formato RTF del codice copiato
      Dim txt As String = Clipboard.GetText(TextDataFormat.Rtf)
      ' con esso inizializza uno StringBuilder
      Dim sb As New StringBuilder(txt)
      ' trova la posizione di inizio del testo
      Dim i As Integer = txt.IndexOf("\fs20 ") + 6
      ' e rimuove il resto
      sb.Remove(0, i)
      ' rimuove le fine-paragrafo
      sb.Replace("\par", "")
      ' trova l'ultima parentesi graffa
      For i = sb.Length - 1 To 0 Step -1
        If sb.Chars(i) = "}"c Then Exit For
      Next
      ' e la elimina
      sb.Length = i - 1
      ' per ognuno dei colori possibili, sostituisce i codici RTF con i tag HTML
      For i = 16 To 1 Step -1
        sb.Replace("\cf" & (i).ToString & " ", "</span><span style=""color:" & colors(i - 1) & """>")
      Next
      ' idem per il colore di default
      sb.Replace("\cf0 ", "</span><span style=""color:none"">")
      ' inserisce l'inizio
      sb.Insert(0, "<pre><span style=""color:none"">")
      ' appende la coda
      sb.Append("</span></pre>")
      ' copia il risultato
      Clipboard.SetText(sb.ToString)
    End If
  End Sub

 Lo scherzo
Naturalmente, questa conversione funziona bene in modo accettabile per quasi tutto il codice che si può copiare da VS, tranne... il proprio! Infatti il codice di CopyAsHtml contiene sia i tag RTF da sostituire che i tag Html che li sostituiscono, che vengono eliminati gli uni dal metodo stesso, e gli altri dal browser, che li interpreta come tali e non letteralmente. Ho dovuto apportare (spero proprio per l'ultima volta) le modifiche a mano.

Conclusione
In un paio d'ore, la maggior parte delle quali trascorse a studiare, più che a scrivere, ho realizzato il mio primo addin. Sicuramente ci sarà bisogno di qualche ritocco, ma al momento mi sembra di aver risolto il mio problema.
Servisse pure ad altri blogger o scrittori di articoli, è scaricabile dall'area download.

Print | posted @ domenica 1 aprile 2007 17:10

Comments on this entry:

Gravatar # re: Il mio primo Addin per Visual Studio 2005
by Diego rimedia at 09/04/2007 20:04

Com'era previsto, ho già ritoccato il codice, per convertire in html alcuni simboli (le graffe, minore e maggiore, tabulazioni).
Ho salvato le modifiche nella stessa posizione
Gravatar # re: Il mio primo Addin per Visual Studio 2005
by Diego rimedia di nuovo at 13/04/2007 21:37

mi sono accorto che i colori usati non sono sempre gli stessi, e che bisogna leggere il vettore di colori ogni volta.
Ho modificato il codice dell'addin, salvandolo nella stessa posizione.
(io scrivo, qua, ma pare che non interessi ad alcuno, il mio addin, perché nessuno s'è preoccupato di rilevare i difetti)
Comments have been closed on this topic.