Code formatter plugin per Live Writer: Up and running!

Beh, come prima esperienza su Visual Studio devo dire che me la sono proprio goduta tutta.

Come primo compitino, visto che il Code Formatter Plugin di Mike Ormond non funziona quando gli chiedi di includere gli stili CSS, mi sono caricato i sorgenti del suddetto plugin e quelli del CSharpFormat di Jean-Claude Manoli in una Solution.

Era la prima volta, quindi ho sudato un pochino per capire come referenziare la ddl del Code Formatter nel progetto di plugin, per poi scoprire che è sin troppo facile: nella Cartella Riferimenti, click del tasto destro su CSharpFormat per mostrare la finestra di dialogo che ti consente di impostare il riferimento, selezionare il tab Progetti, cliccare sul progetto CScharpFormat... et voilà, il gioco è fatto.

Ora si trattava di capire cosa non funzionava. Era il plugin che ignorava l'opzione di inclusione degli stili CSS? o era il codice di Manoli che non funzionava?

Dopo una prima lettura del sorgenti e un paio di test ho escluso il plugin dalla lista dei sospetti e ho concentrato la mia attenzione sul progetto CSharpFormat e in particolare sul sorgente della classe astratta SourceFormat.cs che definisce il metodo FormatCode dove viene implementata la generazione di una stringa contenente il codice formattato in HTML.

Poichè anche qui tutto mi sembrava regolare, ho provato ad utilizzare il plugin in WLW, però utilizzando la view HTML al posto della Normal.

E qui ho fatto la mia scoperta. Il plugin genera correttamente il testo html, incluso il tag <style type="text/css"> ... </style> . Ma allora?

Allora è il WLW (che è ancora una beta!) che in modalità View|Normal si comporta in modo strano:

Quando il plugin gli restituisce il newContent, cioè la stringa di testo HTML da inserire, lui:

  • aggiunge <p></p>
  • della stringa newContent scarta tutto ciò che antecede <p> o <div> o <br> (o altro ancora che non ho provato) col bel risultato di mangiarsi tutta la definizione degli stili!

Quindi, visto che è un'anomalia di WLW, non ho toccato il progetto CSharpFormat mentre ho modificato il Code Formatter Plugin, anteponendo la stringa "<br>" al newContent.

Poi però mi sono accorto che dopo aver utilizzato il plugin, se continuavo a scrivere nel blog, continuavo in realtà a scrivere all'interno del <div>...</div> generato dal code formatter. Niente paura: mi è bastato aggiungere i tags <p></p> alla fine del newContent e anche questo fastidioso effetto è stato sistemato.

Inoltre, poichè uso sempre le opzioni Embed CSS e Banding, ho impostato a true le proprietà checked dei corrispondenti checkbox nel form OptionsForm.cs, così quando uso il plugin me le trovo già settate.

Ecco il sorgente PlugIn.cs, da me modificato:


/* 
 * Copyright (C) 2006 Microsoft Corporation.  All Rights Reserved.
 *
 * This source code is intended only as a supplement to Microsoft
 * Development Tools and/or on-line documentation.  See these other
 * materials for detailed information regarding Microsoft code samples.
 * 
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 *
 * This Live Writer Add-In uses the C# Code Format tool from http://www.manoli.net
 * For details of the C# Code Format tool and the source, visit http://www.manoli.net
 * 
 */
 
using System;
using System.Collections.Generic;
using System.Text;
using WindowsLive.Writer.Api;
using System.Windows.Forms;
using Manoli.Utils.CSharpFormat;
 
namespace LiveWriterCodeFormatterPlugIn
{
    [WriterPlugin("C05C0F49-1A70-40e0-A81E-3750C1CDF85E", 
        "Code Formatter",
        ImagePath = "Images.Code1.png",
        PublisherUrl = "http://www.officedinosaur.com",
        Description = "Helps insert formatted code in your postings")]
 
    [InsertableContentSource("Formatted Code...")]
    public class PlugIn : ContentSource
    {
        private FormatSettings settings = new FormatSettings();
 
        public override DialogResult CreateContent(IWin32Window dialogOwner, ref string newContent)
        {
            using (OptionsForm insertForm = new OptionsForm(settings))
            {
                SourceFormat formatter;
                DialogResult result = insertForm.ShowDialog();
                if (result == DialogResult.OK)
                {
                    switch (settings.FormatLanguage)
                    {
                        case Language.VB:
                            formatter = new VisualBasicFormat();
                            break;
                        case Language.HTML:
                            formatter = new HtmlFormat();
                            break;
                        case Language.TSql:
                            formatter = new TsqlFormat();
                            break;
                        case Language.JavaScript:
                            formatter = new JavaScriptFormat();
                            break;
                        case Language.CPP:
                            formatter = new CPlusPlusFormat();
                            break;
                        default:
                            formatter = new CSharpFormat();
                            break;
                    }
 
                    formatter.Alternate = settings.Banding;
                    formatter.EmbedStyleSheet = settings.EmbeddStyleSheet;
                    formatter.LineNumbers = settings.LineNumbers;
                    formatter.TabSpaces = (byte)settings.TabWidth;
 
                    StringBuilder sb = new StringBuilder();
 
                    // Added the tag <br> as a workaround for the strange behaviour of WLW that ignore
                    // all the newContent text before a <p> or <div> or <br> tags (among others).
                    // Due to this behaviour, without the added <br>, the WLW will skip all
                    // the <style type="text/css"> ... </style> section added by the EmbeddStyleSheet
                    // option. Note that this is not necessary if we switch to the HTML Code View
                    // before using the plugin, but forcing the user to switch view back and forth
                    // IMHO is not a viable workaround in terms of usability.
                    sb.Append("<br>");
 
                    // Added a comment with author citation
                    sb.Append("<!-- code formatted by http://manoli.net/csharpformat/ -->\n");
 
                    sb.Append(formatter.FormatCode(Clipboard.GetText()));
 
                    // Added tags <p></p> to avoid typing (in WLW after using the plugin) inside
                    // the <div> ... </div> code format section 
                    sb.Append("<p>");
                    sb.Append("</p>");
                    
                    newContent = sb.ToString();
                }
                return result;
            }
 
        }
    }
}

Ora si che funziona!

E me ne vado a ninna, prima del solito... me lo sono meritato!

«gennaio»
domlunmarmergiovensab
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910