Aptana Journal #4: Meningkatkan Content Assist


Pada tulisan Aptana Journal #2: Menampilkan Info Untuk Content Assist, saya mencoba membuat Aptana Studio menampilkan context info untuk method polymorphism di JavaScript (dengan contoh berupa jQuery).  Gambar berikut ini memperlihatkan hasil perubahan:

Menampilkan Context Info Untuk Method Polymorphism

Menampilkan Context Info Untuk Method Polymorphism

Pada pendekatan tersebut, content assist yang muncul tetap hanya berisi satu (1) method saja.  Begitu pengguna mengetik tanda kurung buka, maka pilihan parameter akan muncul.

Saya merasa bahwa hal tersebut masih dapat diperbaiki.  Pada kesempatan ini, saya kembali ingin melakukan perubahan dimana saya mengharapkan seluruh method polymorphism dengan nama yang sama akan muncul di content assist (bukan pada saat pengguna mengetik kurung buka).

Saya pun kembali melakukan penelusuran di file com.aptana.editor.js/src/com/aptana/editor/js/contentassist/JSContentAssistProcessor.java.  Di method doComputeCompletionProposals(ITextViewer, int, char, boolean), terdapat pemanggilan ke method addProjectGlobals() yang akan menambahkan proposal untuk jQuery.  Saya ingin segala bentuk polymorphism (dokumentasi method dengan nama yang sama tetapi memiliki parameter yang berbeda) disertakan sebagai objek completion proposal yang berbeda.

Isi dari method addProjectGlobals() adalah:

private void addProjectGlobals(Set<ICompletionProposal> proposals, int offset)
{
  Collection<PropertyElement> projectGlobals = indexHelper.getGlobals(getIndex(), getProject(), getFilename());

  if (!CollectionsUtil.isEmpty(projectGlobals))
  {
    String[] userAgentNames = getActiveUserAgentIds();
    URI projectURI = getProjectURI();

    for (PropertyElement property : CollectionsUtil.filter(projectGlobals, isVisibleFilter))
    {				
      String location = null;				
      List<String> documents = property.getDocuments();
      if (!CollectionsUtil.isEmpty(documents))
      {
        String docString = documents.get(0);
        int index = docString.lastIndexOf('/');
        if (index != -1)
        {
          location = docString.substring(index + 1);
        }
        else
        {
          location = docString;
        }
      }
      addProposal(proposals, property, offset, projectURI, location, userAgentNames);
    }
  }
}

Setelah menghabiskan waktu di method ini, saya tidak menemukan ada sesuatu yang salah.  Seharusnya setiap dokumentasi polymorphis memang akan didaftarkan sebagai completion proposal yang berbeda.  Mengapa yang terjadi tidak demikian?

Setelah menghabiskan waktu yang cukup lama, akhirnya saya menemukan jawabannya.  Seluruh completion proposal yang perlu ditampilkan akan ditampung dalam sebuah Set.   Struktur data Set adalah himpunan dimana tidak boleh mengandung elemen yang sama. Tapi bukankah setiap completion proposal pasti adalah elemen baru karena pada method addProposal() terdapat baris new PropertyElementProposal()? Iya, memang demikian. Tapi bila terdapat method equals(), maka Java akan menentukan dua buah objek adalah objek yang sama atau tidak berdasarkan method tersebut.   Masalahnya, PropertyElementProposal adalah turunan dari CommonCompletionProposal; kemudian CommonCompletionProposal mengandung method equals(); tetapi method PropertyElementProposal tidak memiliki method equals().   Dengan demikian, saat akan menambah PropertyElementProposal ke dalam Set, untuk menentukan apakah elemen sudah ada, yang dibandingkan adalah setiap atribut yang ada pada CommonCompletionProposal bukan sesuatu yang spesifik di PropertyElementProposal.   Hal ini menyebabkan beberapa dokumentasi polymorphism akan diabaikan.

Untuk mengatasi “bug” di atas (yup! ini adalah bug yang cukup menipu!), saya perlu menambahkan method equals() pada PropertyElementProposal.   Agar cepat, saya memilih menu Source, Generate hashCode() and equals()… di Eclipse RCP.

Sampai disini, Set sudah berisi proposal sesuai dengan yang diharapkan.  Loh?  Tapi kenapa  di content assist yang ditampilkan masih tetap satu proposal saja?   Setelah melakukan penelurusan, saya menemukan bahwa telah terjadi sesuatu di method getMergedProposals() terutama di bagian berikut ini:

protected List getMergedProposals(List<ICompletionProposal> proposals) 
{
   ...
   return CollectionsUtil.filter(proposals, new ProposalMerger());
}

Berikut ini adalah isi class ProposalMerger yang dipakai oleh kode program di atas:

public class ProposalMerger implements IFilter<ICompletionProposal>
{
  private ICompletionProposal lastProposal = null;

  public boolean include(ICompletionProposal item)
  {
    boolean result;
    if (lastProposal==null || !lastProposal.getDisplayString().equals(item.getDisplayString()))
    {
       result = true;
       lastProposal = item;
    }
    else 
    {
       result = false;
    }
  }
}

Method include() akan dikerjakan terhadap setiap elemen di Set yang berisi ICompletionProposal yang telah diurutkan.  Jika saya memperhatikan secara lebih lanjut, method tersebut akan menolak elemen dengan getDisplayString() yang sama.  Hal ini tidak sesuai dengan tujuan awal saya, karena saya ingin mengizinkan dokumentasi polymorphism.  Oleh sebab itu, saya mengubah kode program di atas sehingga terlihat menjadi seperti berikut ini:

public class ProposalMerger implements IFilter<ICompletionProposal>
{
  private ICompletionProposal lastProposal = null;

  public boolean include(ICompletionProposal item)
  {
    boolean result;
    if (lastProposal==null || !lastProposal.getDisplayString().equals(item.getDisplayString()))
    {
       result = true;
       lastProposal = item;
    }
    else 
    {
       if (lastProposal instanceof PropertyElementProposal) {
          result = true;
          lastProposal = item;
       } else {       
          result = false;
       }
    }
  }
}

Sekarang, tampilan content assist akan terlihat seperti berikut ini:

Tampilan Content Assist Setelah Perubahan

Tampilan Content Assist Setelah Perubahan

Walaupun sudah hampir mencapai seperti keinginan saya, masih ada beberapa hal yang perlu diperbaiki lagi.  Salah satunya adalah menentukan mana yang harus dipakai, hasil parsing dari file JavaScript atau hasil parsing dari ScriptDoc XML.  Pada gambar di atas, seharusnya hanya dua proposal yang ditampilkan yang berasal dari ScriptDoc XML, sementara hasil parsing dari file jquery-1.8.3.js tidak perlu ditampilkan (karena tidak mengandung dokumentasi).

Perihal Solid Snake
I'm nothing...

One Response to Aptana Journal #4: Meningkatkan Content Assist

  1. Ping-balik: Aptana Journal #9: Mengorbankan Static Method « The Solid Snake

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: